2012-08-09 2 views
0

У меня есть два класса: OuterClass и InnerClass. InnerClass является частным членом OuterClass и должен быть создан в конструкторе OuterClass с конструктором InnerClass (int), однако по умолчанию конструктор InnerClass по-прежнему вызывается.Объект InnerClass, являющийся членом объекта OuterClass, создается дважды

InnerClass.hpp:

#ifndef INNERCLASS_HPP_ 
#define INNERCLASS_HPP_ 

class InnerClass { 
public: 
    int a; 
    InnerClass(); 
    InnerClass(int); 
    ~InnerClass(); 
}; 

#endif /* INNERCLASS_HPP_ */ 

InnerClass.cpp:

#include "InnerClass.hpp" 
#include <iostream> 

InnerClass::InnerClass() { 
    a = 1; 
    std::cout << "inner class constructed, a = " << a << std::endl; 
} 
InnerClass::InnerClass(int x) { 
    a = x; 
    std::cout << "inner class constructed, a = " << a << std::endl; 
    //automatically: object InnerClass (a=3) is destroyed here... 
} 
InnerClass::~InnerClass() { 
    std::cout << "inner class destructed, a = " << a << std::endl; 
} 

OuterClass.hpp:

#ifndef OUTERCLASS_HPP_ 
#define OUTERCLASS_HPP_ 

#include "InnerClass.hpp" 

class OuterClass { 
private: 
    InnerClass blah; 
public: 
    OuterClass(); 
    ~OuterClass(); 
    void doSth(); 
}; 

#endif /* OUTERCLASS_HPP_ */ 

OuterClass.cpp:

#include "OuterClass.hpp" 
#include <iostream> 

OuterClass::OuterClass() { 
    // automatically: blah = InnerClass(); 
    std::cout << "outer class constructing started, blah.a = " << blah.a << std::endl; 
    blah = InnerClass(3); 
    std::cout << "outer class constructed" << std::endl; 
} 

OuterClass::~OuterClass() { 
    std::cout << "outer class destructed" << std::endl; 
} 

void OuterClass::doSth() { 
    std::cout << "doSth: " << blah.a << std::endl; 
} 

главная:

#include "OuterClass.hpp" 
#include <iostream> 

int main(int argc, char** argv) { 
    std::cout << "Compiled at " << __TIME__ << std::endl; 

    OuterClass x = OuterClass(); 
    x.doSth(); 

    std::cout << "done" << std::endl; 
} 

выход:

Compiled at 12:11:12 
inner class constructed, a = 1 //this is unexpected 
outer class constructing started, blah.a = 1 //this should be random data 
inner class constructed, a = 3 
inner class destructed, a = 3 //this is unexpected 
outer class constructed 
doSth: 3 
done 
outer class destructed 
inner class destructed, a = 3 

Вопросы:

  1. Почему конструктор по умолчанию InnerClass вызывается в начале OuterClass конструктора?
  2. Что и почему разрушено в конструкторе OuterClass («внутренний класс разрушен, a = 3 // это неожиданно»)?
  3. Похоже, что объект InnerClass с a = 3 был разрушен в конструкторе OuterClass, чем почему метод doSth() возвращает 3 вместо случайных данных?
  4. Почему удаление конструктора InnerClass() (из файлов InnerClass.hpp и InnerClass.cpp) приводит к ошибке времени компиляции в конструкторе OuterClass в файле OuterClass.cpp? Ошибка говорит о том, что определение InnerClass() не найдено.
+0

Я думаю, вы должны были использовать InnerClass * blah? Тогда не будет никакой двойной конструкции. InnerClass blah автоматически создаст локальный экземпляр при создании, который вы перезапишете в конструкторе. В конце концов он разрушен (вместо того, чтобы стать утечкой mem (ну, даже те, которые становятся понятны после выхода приложения)), поскольку он имеет локальную область действия, как только весь объект деконструируется. --- Кстати, ваш код правильный? blah = InnerClass (3); должен вызвать нового оператора ??? –

ответ

4

Использовать список инициализаторов в конструкторе.

OuterClass::OuterClass() : blah(3) { 
    // automatically: blah = InnerClass(); 
    std::cout << "outer class constructing started, blah.a = " << blah.a << std::endl; 
    std::cout << "outer class constructed" << std::endl; 
} 

Поскольку при использовании

OuterClass::OuterClass() { 
    // automatically: blah = InnerClass(); 
    std::cout << "outer class constructing started, blah.a = " << blah.a << std::endl; 
    blah = InnerClass(3); 
    std::cout << "outer class constructed" << std::endl; 
} 

во-первых, для инициализации бэ будет называться по умолчанию с-тор и в blah = InnerClass(3);, что создает временный объект и скопировать его в мля, после этого строка будет называться деструктор временного объекта.

+0

Я действительно не понимаю, почему он переопределяет существующий объект с новым значением a равно 3. Я бы понял, был ли «разрушающий объект с a = 1». –

+0

@JaroslawPawlak in blah = InnerClass (3); operator = для вызываемого InnerClass, по умолчанию оператор = копирует значения элементов объекта, которые остаются в правой части назначения объекту, который остается в левой части назначения, и возвращает ссылку на * это (левая сторона объекта назначения), когда он возвращает, временный объект выходит за пределы области действия и разрушается. – ForEveR

0
OuterClass::OuterClass() /* default blah constructor is called here */ { 
    std::cout << "outer class constructing started, blah.a = " << blah.a << std::endl; 
    blah = InnerClass(3); /* a temporary InnerClass is created */ 
    std::cout << "outer class constructed" << std::endl; 
} //temporary InnerClass destroyed (out of scope) 

Использование initializer list предотвратить вызов конструктора по умолчанию, как НАВСЕГДА предлагает

2

1) Почему конструктор по умолчанию InnerClass вызывается в начале OuterClass конструктора?

Для строительства blah.

2) Что и почему разрушено в конструкторе OuterClass («внутренний класс разрушен, a = 3 // это неожиданно»)?

InnerClass(3), который вы построили во второй строке конструктора. Тот, который вы использовали для хранения значения, которое вы присвоили blah. Он разрушен, потому что он выходит за пределы области после завершения задания blah.

3) Кажется, что объект InnerClass с a = 3 был разрушен в конструкторе OuterClass, чем почему метод doSth() возвращает 3 вместо случайных данных?

Потому что вы присвоили значение 3 - blah. Ваш код читается;

blah = InnerClass(3);

Это создает InnerClass со значением 3, а затем копирует его значение в blah. Таким образом, оба значения blah и этот временный объект имеют одинаковое значение. Временное уничтожается.

Если вы думаете об этом, нет другого разумного способа реализовать эту строку кода.

4) Почему удаление InnerClass() конструктор (с обеих InnerClass.hpp и InnerClass.cpp файлов) приведет к ошибке времени компиляции в конструкторе OuterClass в OuterClass.cpp файл? Ошибка говорит о том, что определение InnerClass() не найдено.

Потому что тогда у вас нет способа построить blah в первую очередь. (Как уже отмечалось, вы, вероятно, хотел список инициализатора построить blah право в первую очередь, а не по умолчанию его построения, а затем, чтобы идти в судорогах, чтобы исправить это.)

0
  1. Когда конструктор OuterClass начинает выполнять тело, все члены должны быть построены. Поскольку есть член blah InnerClass, он был построен.

  2. Когда вы назначаете blah в OuterClass :: OuterClass(), создается временный экземпляр. Вот порядок вещей:

    • Построен временный InnerClass (3).
    • Относится к blah.
    • Временное значение разрушено - вот почему есть вызов деструктора.
  3. От 2: blah имеет значение 3 в присвоении, указанном в № 2 выше.

  4. Было указано, что в C++, если у вас есть объявленные конструкторы конструктивных аргументов, конструктор по умолчанию больше не создан за вашей спиной компилятором. Я не могу сейчас заглянуть в соответствующее место в стандарте прямо сейчас, редакторы не стесняйтесь исправить это.

Он бы помог вам, если вы инструментальными InnerClass следующим образом:

  1. Держите статический счетчик экземпляра, и скопировать его в каждом конкретном случае. Таким образом, вы узнаете, какой экземпляр сообщает об этом.

  2. Вручную напишите InnerClass & operator=(const InnerClass &), чтобы увидеть, когда он вызывается.

0

(PS: Вы приезжаете из Java World на C++, случайно?)

Выход объяснил:

inner class constructed, a = 1 //this is unexpected 

InnerClass построен с конструктором по умолчанию первый

outer class constructing started, blah.a = 1 //this should be random data 

Это значение InnerClass строится на предыдущем шаге с умолчанию CTOR

inner class constructed, a = 3 

Временный InnerClass построен с перегруженной CTOR и назначен членом бэ (неявного оператора = называется - вы можете проверить перегрузки оператор =)

inner class destructed, a = 3 //this is unexpected 

временный InerClass созданный на предыдущем шаге разрушается

outer class constructed 
doSth: 3 
done 
outer class destructed 
inner class destructed, a = 3 

Ответы:

Почему конструктор InnerClass по умолчанию вызывает в начале Конструктор OuterClass?

Поскольку у вас есть член InnerClass. Вы должны сделать это указателем или использовать список инициализаторов.

OuterClass::OuterClass() 
: blah(3) 
{ 
    // automatically: blah = InnerClass(); 
    std::cout << "outer class constructing started, blah.a = " << blah.a << std::endl; 
    // blah = InnerClass(3); 
    std::cout << "outer class constructed" << std::endl; 
} 

Что и почему разрушается в OuterClass конструктор ("внутренний класс разрушен, а = 3 // это неожиданное")?

Временный InnerClass разрушен здесь.

Кажется, что InnerClass объект с = 3 был разрушен в OuterClass конструктора , чем почему метод doSth() возвращают 3 вместо случайных данных?

Член мля теперь имеет копию объекта InnerClass со значением 3

Почему удаление InnerClass() конструктор (с обеих InnerClass.hpp и InnerClass.cpp файлов) результат компиляции ошибка в конструкторе OuterClass в файле OuterClass.cpp?Ошибка говорит, что не найдено определения InnerClass() .

Вы имеете в виду удаление конструктора по умолчанию. Да, ошибка ожидается, потому что элемент blah сначала создается с по умолчанию ctor.

Смежные вопросы