Альтернатива предописаниям, когда Вы не хотите к #include

Почему вам нужно использовать Python? Я думаю, что самый простой способ - написать макрос в VBA Excel (который может обновлять значения на вашем листе), а затем распечатать его в формате PDF или.

10
задан sharkin 20 November 2008 в 16:28
поделиться

10 ответов

Просто используйте интеллектуальный указатель - можно даже использовать auto_ptr в этом случае.

//-----------------------
// bar.h
//-----------------------

#include <memory>
class foo;       // Not enough given the way we declare "foo_object"..

class bar
{
public:
   bar();
   ~bar();

   foo &foo_object() { return *foo_ptr; }
   const foo &foo_object() const { return *foo_ptr; }

private:
   auto_ptr<foo> foo_ptr;
};

Вы извлекаете всю пользу из автоматического управления памятью, не имея необходимость знать что-либо о нечто в bar.h. Посмотрите Переносящиеся Элементы данных Указателя для рекомендации Herb Sutter.

Если Вы действительно хотите, чтобы конструкция по умолчанию произошла автоматически, попробуйте это:

#include <iostream>
using namespace std;

class Foo;

template <typename T>
class DefaultConstuctorPtr
{
    T *ptr;
    void operator =(const DefaultConstuctorPtr &);
    DefaultConstuctorPtr(const DefaultConstuctorPtr &);

public:
    DefaultConstuctorPtr() : ptr(new T()) {}
    ~DefaultConstuctorPtr() { delete ptr; }

    T *operator *() { return ptr; }
    const T *operator *() const { return ptr; }
};

class Bar
{
    DefaultConstuctorPtr<Foo> foo_ptr;
public:
    Bar() {} // The compiler should really need Foo() to be defined here?
};

class Foo
{
public:
    Foo () { cout << "Constructing foo"; }
};

int main()
{
    Bar bar;
}
7
ответ дан 3 December 2019 в 15:07
поделиться

Если Вы можете использовать ссылку, можно сохранить тот же синтаксис использования. Однако Ваша ссылка должна быть немедленно инициализирована в конструкторе, таким образом, Ваш ctor абсолютно должен быть определен исключительный. (Необходимо будет также освободить объект в деструкторе также.)

// bar.h
class foo;

class bar {
    foo& foo_;

public:
    bar();
    ~bar();
};

// bar.cc
bar::bar() : foo_(*new foo)
{
    // ...
}

bar::~bar()
{
    // ...
    delete &foo_;
}

Ваш пробег может варьироваться.:-)

0
ответ дан 3 December 2019 в 15:07
поделиться

Нет никакого пути вокруг этого.

Ваш лучший выбор состоит в том, чтобы ограничить, сколько включено, но необходимо включать файл с объявлением класса. Вы могли, мог разделить класс declarationout на отдельный заголовок, который, надо надеяться, не включает ничто иное. Затем да, у Вас должен быть #include, но Вы все еще сохраняете Ваш включать несколько мелкую иерархию. В конце концов, включая один файл является дешевым, это только, когда иерархия растягивается к сотням или тысячам файлов, которые это начинает повреждать... ;)

1
ответ дан 3 December 2019 в 15:07
поделиться

Поскольку другие заявили, что Вы не можете сделать этого по причинам, которые они заявили также :) Вы затем сказали, что не хотите заботиться о членской конструкции / разрушение в классе, содержащем их. Можно использовать шаблоны для этого.

template<typename Type>
struct member {
    boost::shared_ptr<Type> ptr;
    member(): ptr(new Type) { }
};

struct foo;
struct bar {
    bar();
    ~bar();

    // automatic management for m
    member<foo> m;
};

Я думаю, что код сам объяснительный. Если какие-либо вопросы возникают, прослушивают меня.

2
ответ дан 3 December 2019 в 15:07
поделиться

В значительной степени единственная вещь, которую можно сделать, минимизируют влияние при помощи pImpl идиомы так, чтобы при включении foo.h Вы только включали интерфейс нечто.

Вы не можете избежать включая foo.h, но можно сделать его максимально дешевым. Привычка Вы разработали использования foward объявления, а не #inlcudes, имеет Вас хорошо на этом пути.

1
ответ дан 3 December 2019 в 15:07
поделиться

То, что Вы хотите, не может быть сделано в C++. Чтобы сгенерировать код для объекта, Ваш компилятор должен знать, какого количества устройства хранения данных его класс требует. Чтобы знать, что, это должно знать, сколько устройства хранения данных требуется для каждого члена класса.

Если Вы хотите создать класс печатающей штанги с членом нечто типа, компилятор должен знать, насколько большой нечто. Единственным путем это знает, что это - то, если это имеет определение в наличии нечто (через #include). Иначе Ваша единственная опция состоит в том, чтобы использовать предописание нечто и указателя или ссылки вместо фактического объекта нечто.

7
ответ дан 3 December 2019 в 15:07
поделиться

Вы не можете. Компилятор должен знать размер объекта при объявлении класса.

Ссылки являются альтернативой, хотя они нужно инстанцировать во время создания, таким образом, это не всегда выполнимо.

Другая альтернатива является интеллектуальными указателями, но я предполагаю, что это - технически все еще указатель.

Было бы хорошо знать, почему Вы не хотите использовать указатель для предложения некоторой другой конструкции хотя...

12
ответ дан 3 December 2019 в 15:07
поделиться

Вы могли использовать пользовательский класс "интеллектуального указателя", который автоматически создает и уничтожает экземпляр. Это достигло бы автоматической конструкции и разрушения, которое Вы после.

Для предотвращения потребности в другом #include можно включать это myAuto класс в заголовке префикса для Вашего проекта, или можно скопировать и вставить его в каждый заголовок (не хорошая идея, но он работал бы).

template<class T>
class myAuto
{
    private:
        T * obj;

    public:
        myAuto() : obj(new T) {  }
        ~myAuto() { delete obj; }
        T& object() { return *obj; }
        T* operator ->() { return obj; }
};

Вот то, как Вы использовали бы его:

// foo.h:
class foo
{
    public:
        foo();
        ~foo();
        void some_foo_func();
};
//bar.h:
class foo;
class bar
{
    public:
       bar();
       ~bar();
       myAuto<foo> foo_object;
};
//main.cc:
#include "foo.h"
#include "bar.h"

int main()
{
    bar a_bar;

    a_bar.foo_object->some_foo_func();

    return 0;
}
0
ответ дан 3 December 2019 в 15:07
поделиться

Вы могли также использовать pImpl идиому, например:

//-----------------------
// foo.h
//-----------------------
class foo
{
    foo();
    ~foo();
};


//-----------------------
// bar.h
//-----------------------

class foo;

class bar
{
private:
    struct impl;
    boost::shared_ptr<impl> impl_;
public:
    bar();

    const foo& get_foo() const;
};

//-----------------------
// bar.cpp
//-----------------------
#include "bar.h"
#include "foo.h"

struct bar::impl
{
    foo foo_object;
    ...
}

bar::bar() :
impl_(new impl)
{
}

const foo& bar::get_foo() const
{
    return impl_->foo_object;
}

Вы все еще извлекаете пользу из предописаний, плюс Вы скрывают Вашу частную реализацию. Изменения в реализации панели не обязательно потребуют компиляции всех исходных файлов это #include bar.h. Сама структура реализации является автономной в .cpp файле, и здесь можно объявить объекты к содержанию основ.

Вам поражали маленькую производительность из-за самого pImpl, но в зависимости от приложения это не могло бы быть грандиозным предприятием.

Я использовал pImpl идиому для крупных проектов, и она имеет большое значение ко времени компиляции. Жалость язык, не может обработать действительно частную реализацию, но там у Вас есть он.

0
ответ дан 3 December 2019 в 15:07
поделиться

Существует действительно только три альтернативы для соединения двух объектов. Вы уже обнаружили два: встройте Foo в Панель, или поместите Foo на "кучу" и поместите Нечто* в Панель. Первое требует класса определения Foo прежде, чем определить класс Панель; второе просто требует, чтобы Вы для передачи объявили класс Foo.

Третья опция действительно существует, который я только упоминаю, потому что Вы конкретно исключаете обе предыдущих опции в своем вопросе. Вы можете (в Вашем .cpp), создают статический станд.:: карта. В каждом конструкторе Bar Вы добавляете Нечто к этой карте, включенной this. Каждый участник панели может затем найти связанного Foo путем поиска this в карте. Панель:: ~Bar будет звонить erase(this) уничтожать Нечто.

В то время как это сохраняет sizeof (Панель) неизменный, фактическое использование памяти выше, чем включение Нечто* в Панели. Вы все еще могли бы сделать это, если совместимость на уровне двоичных кодов является нажимающим беспокойством, все же.

0
ответ дан 3 December 2019 в 15:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: