С ++ синтаксис конструкторов "Object1 a (1, Object1 (2))" - PullRequest
2 голосов
/ 27 марта 2010

У меня такой синтаксис в программе

/* The Object1 is allowed to be changed */
class Object1 : BaseClass {
    BaseClass *link;
    int i;
    public: 
    Object1(int a){i=a;}
    Object1(int a, Object1 /*place1*/ o) {i=a; link= &o;}
};

int main(){
/* The initialization syntax must be preserved. No any new(), no other local objects b,c */
    Object1 a(1, /*place2*/ Object1(2));
    ...
}

Что мне нужно на месте1? Я хочу сохранить ссылку (указатель) на второй объект в первом объекте. Должен ли я использовать вместо place1 ссылку "&"?

Какой тип будет иметь «Object1 (2)» вместо place2? Это конструктор анонимного объекта? Будет ли у него «автоматический» тип хранения?

Спасибо

UPDATE:

В place2 синтаксис исправлен, и я действительно должен поддерживать создание «цепочки», как

    Object1 a(1, Object1(2, Object1(6, Object1(999753))));

Я не могу добавить ни одного символа в определение a.

UPDATE2: для place1: Object1(int a, Object1 &o) {i=a; link= &o;} и Object1 a(1, Object1(2)); вместо place2 У меня ошибка компиляции (g ++):

main.cpp||In function `int main()':|
main.cpp|19|error: no matching function for call to `Object1::Object1(int, Object1)'|
main.cpp|9|note: candidates are: Object1::Object1(const Object1&)|
main.cpp|14|note:                 Object1::Object1(int, Object1&)|
main.cpp|13|note:                 Object1::Object1(int)|

Ответы [ 6 ]

4 голосов
/ 27 марта 2010

В "place1" вам нужна ссылка. Object1 не полностью определен, поэтому вы не можете взять его по значению. Тем не менее, вы не хотели бы передавать по значению; когда вы берете его адрес, вы получите адрес копии, а не фактический объект.

Поскольку вам нужен только указатель на BaseClass, возможно, имеет смысл поместить это ограничение только на параметр. (Конечно, если вам действительно нужен Object1, отразите это в виде link: Object1* link;).

Также рассмотрите возможность использования списка инициализации:

Object1(int a) : i(a), link(0) /* <- important! */ { }
Object1(int a, BaseClass& o) : i(a), link(&o) { }

Всегда используйте список инициализации.

"place2" создает безымянный экземпляр Object1, используя конструктор. У него нет памяти (?) auto памяти, а умирает в конце выражения .

То есть, после того как вы нажали точку с запятой в Object1 a(1, /*place2*/ Object1(2));, она перестает существовать, и у вас есть указатель на несуществующий объект! Это приводит к неопределенному поведению.

Дайте ему жизнь вне выражения:

Object1 x(2);    
Object1 a(1, x);

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


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

Опять же, ваш дизайн требует доработки, к сожалению.

2 голосов
/ 27 марта 2010

Место 1: используйте указатель (*) вместо ссылки (&) здесь. Синтаксис указателя более явно указывает на ссылку.

Место 2: здесь будет создан так называемый «временный» объект. Да, это будет связано с вызовом конструктора Object1. Кроме того, да, хранилище будет «автоматическим», поскольку оно будет создано в стеке.

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

Если вам необходимо передать временное сообщение, вы можете добиться успеха, создав его копию в куче. Примерно так:

class Object1
{
    BaseClass* link;
    int i;
    Object1(int a) : i(a), link(NULL) {}
    Object1(int a, const Object1& o) : i(a), link(new new Object1(o)) {} 
    Object1(const Object1& other) i(other.i) link(other.link) {} //Copy constructor
    virtual ~Object1() { delete link; } //Don't forget the 'delete' in destructor.
};

Тогда в своей главной вы можете () сделать это:

int main() 
{
    Object1 a(3, Object1(2));
    ....
}

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

Также убедитесь, что деструктор виртуален. Это потому, что вы будете вызывать delete на указателе базового класса, который указывает на объект производного класса.

0 голосов
/ 27 марта 2010

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

Вы можете реорганизовать свой код с помощью рекурсии и сохранить связанный список в стеке, но это не будет очень C ++ -ish.

В противном случае, единственное решение - использовать кучу (std::list, std::auto_ptr или std::unique_ptr должны сделать трюк), как предлагали другие.

0 голосов
/ 27 марта 2010

То, что вы хотите сделать, невозможно, как вы это написали. Время жизни Object1 в /*place2*/ заканчивается после того, как конструктор делает, поэтому у вас будет висячий указатель.

В общем, вам нужно, чтобы Object1 в /*place2*/ был ссылкой или указателем напрямую [в этом случае вы не берете адрес, просто скопируйте его напрямую].

Но вы должны быть очень осторожны с временем жизни указателя, который вы храните, о чем свидетельствует начальная точка.

0 голосов
/ 27 марта 2010

Аргумент конструктора o является копией экземпляра Object1, который вы передали (поскольку он передается значением . В вашем конструкторе, когда вы устанавливаете свой член указатель на его адрес, этот адрес является фреймом стека, который станет недействительным после того, как ваш конструктор вернет.

Вот еще один способ сделать это (конечно, есть и другие способы):

class Object1 : BaseClass
{
    BaseClass *link;
    int i;

public: 
    // - Prefer initialization to assignment
    // - Initialize ALL of your members
    Object1(int a) : link(NULL), i(a) {}

    // This instance assumes ownership of p
    Object1(int a, Object1 *p) : link(p), i(a) {}

    ~Object1() { delete link; }
};

int main()
{
    Object1 a(1, new Object1(2));
    ...
}

РЕДАКТИРОВАТЬ: Хммммм, я вижу, как вы можете использовать ваш дизайн цепочки, это что-то уродливое:

class Object1 : BaseClass
{
    BaseClass *link;
    int i;

public:
    Object1(int a) : link(NULL), i(a) {}

    Object1(int a, const Object1& o) : link(new Object1(o)), i(a) {}

    // Copy constructor
    Object1(const Object1& other) : link(NULL), i(other.a)
    {
        // Deep copy linked object
        if (other.link != NULL)
        {
            link = new Object1(*other.link);
        }
    }

    // Assignment operator that does deep copy
    const Object1& operator=(const Object1& that)
    {
        // Check for assignment to self
        if (this != &that)
        {
            delete this.link; 
            this.link = NULL;

            // Deep copy linked object
            if (that.link != NULL)
            {
                this.link = new Object1(*that.link);
            }

            this.i = that.i;
        }
    }

    ~Object1() { delete link; }
};

int main()
{
    Object1 a(1, new Object1(2));
    ...
}
0 голосов
/ 27 марта 2010

Вы не можете использовать экземпляр Object1 в его объявлении (он еще не объявлен). Вы можете добавить нечто, называемое предварительным объявлением, перед объявлением класса, например так:

// Forward declaration
class Object1;

// Now the class body
class Object1 {
    // some reference to Object1 here
};

Однако я до сих пор не совсем понимаю, что вы пытаетесь сделать с этим кодом. Это может помочь получить немного больше информации о том, что вы хотите, чтобы этот конструктор делал? Я подозреваю, что вы, возможно, захотите использовать указатель или передачу по ссылке, а не передачу по значению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...