作为外类对象的成员的内部类对象被创建两次

时间:2012-08-09 11:27:07

标签: c++ constructor destructor

我有两个类:OuterClass和InnerClass。 InnerClass是OuterClass的私有成员,应该使用InnerClass(int)构造函数在OuterClass构造函数中创建,但仍然会调用默认的InnerClass构造函数。

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. 为什么在OuterClass构造函数的开头调用InnerClass的默认构造函数?
  2. 什么和为什么在OuterClass构造函数中被破坏(“内部类被破坏,a = 3 //这是意料之外的”)?
  3. 似乎在OuterClass构造函数中破坏了具有a = 3的InnerClass对象,而为什么方法doSth()返回3而不是随机数据?
  4. 为什么删除InnerClass()构造函数(来自InnerClass.hpp和InnerClass.cpp文件)导致OuterClass.cpp文件中的OuterClass构造函数出现编译时错误?错误表明没有找到InnerClass()定义。

5 个答案:

答案 0 :(得分:4)

在构造函数中使用initializer-list。

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称为默认c-tor,并在blah = InnerClass(3);中创建临时对象并将其复制为blah,此字符串将被称为临时对象的析构函数。

答案 1 :(得分:2)

  

1)为什么在OuterClass构造函数的开头调用InnerClass的默认构造函数?

构建blah

  

2)在OuterClass构造函数中破坏了什么以及为什么(“内部类被破坏,a = 3 //这是意料之外的”)?

您在构造函数的第二行中构造的InnerClass(3)。您用来保存分配给blah的值的那个。它被破坏,因为一旦blah的分配完成,它就会超出范围。

  

3)似乎在OuterClass构造函数中破坏了具有a = 3的InnerClass对象,而为什么方法doSth()返回3而不是随机数据?

因为您已将值3分配给blah。你的代码是:

blah = InnerClass(3);

这会创建一个值为3的InnerClass,然后将其值复制到blah。因此blah和此临时对象都具有相同的值。然后将临时销毁。

如果你考虑一下,没有其他合理的方法来实现这一行代码。

  

4)为什么删除一个InnerClass()构造函数(来自InnerClass.hpp和InnerClass.cpp文件)导致OuterClass.cpp文件中的OuterClass构造函数出现编译时错误?错误说没有找到InnerClass()定义。

因为那时你无法构建blah。 (正如其他人所指出的那样,你可能想要一个初始化列表来构造blah,而不是默认构造它,然后不得不去扭曲修复它。)

答案 2 :(得分: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来阻止调用默认构造函数,因为ForEveR建议

答案 3 :(得分:0)

  1. 当OuterClass的构造函数开始执行主体时,必须构造所有成员。由于存在blah InnerClass成员,因此构建了它。

  2. 在OuterClass :: OuterClass()中分配给blah时,会创建一个临时实例。这是事情的顺序:

    • 构造临时InnerClass(3)。
    • 分配给blah
    • 临时值被破坏 - 这就是析构函数调用的原因。
  3. 从2开始:blah在上面#2中提到的作业中设置为3。

  4. 有人推断,在C ++中,如果你有一个专门的参数 - 采用构造函数声明,那么编译器就不会在你的背后创建默认构造函数了。我现在无法深入研究标准中的相关位置,编辑可以随意纠正这一点。

  5. 如果您按如下方式对InnerClass进行了检测,它会帮助您:

    1. 保留一个静态实例计数器,并将其复制到每个实例。这样你就可以知道哪个实例正在报告。

    2. 手动编写InnerClass & operator=(const InnerClass &)以查看何时调用。

答案 4 :(得分: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

这是使用默认ctor

在上一步中构造的InnerClass的值
inner class constructed, a = 3

使用重载的ctor构造一个临时的InnerClass并分配给blah成员(调用隐式operator = - 你可以通过重载operator =来检查)

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中被破坏     构造函数(“内部类被破坏,a = 3 //这是意料之外的”)?

临时的InnerClass在这里被销毁。

似乎在a = 3中破坏了具有= 3的InnerClass对象     OuterClass构造函数,为什么方法doSth()返回3     而不是随机数据?

blah成员现在有一个值为3的InnerClass对象的副本

为什么删除InnerClass()     构造函数(来自InnerClass.hpp和InnerClass.cpp文件)     导致在OuterClass构造函数中的编译时错误     OuterClass.cpp文件?错误说没有InnerClass()定义     找到。

您的意思是删除默认构造函数。是的,错误是预期的,因为首先使用默认ctor创建了blah成员。