C++ - 构造类中的对象

Sol*_*ear 24 c++ oop constructor

我对C++很新,我不确定这个.看看下面的例子总结了我当前的问题.

class Foo
{
    //stuff
};

class Bar
{
    Foo foo;
};
Run Code Online (Sandbox Code Playgroud)

因此Bar会保留一个完整的Foo对象,而不仅仅是一个引用或指针.此对象是否由其默认构造函数初始化?我是否需要显式调用其构造函数,如果是,请问如何以及在何处?

谢谢.

Fra*_*man 24

它将由其默认构造函数初始化.如果你想使用不同的构造函数,你可能会有这样的东西:

class Foo
{
    public: 
    Foo(int val) { }
    //stuff
};

class Bar
{
    public:
    Bar() : foo(2) { }

    Foo foo;
};
Run Code Online (Sandbox Code Playgroud)

  • :-) uservoice request:代码完成和错误突出显示在降价框上. (5认同)
  • 每个类关闭后的一个半冒号(;).我责备Java. (3认同)
  • 第一句话是错的.Foo的初始化无法保证.这取决于如何为给定的Bar定义Foo.请阅读页面末尾的答案:http://stackoverflow.com/questions/849812/c-construction-of-an-object-inside-a-class/850240#850240 (2认同)

Dav*_*eas 16

构造在C++中是一个相当难的主题.简单的答案取决于它.是否初始化Foo取决于Foo本身的定义.关于第二个问题:如何使Bar初始化Foo:初始化列表就是答案.

虽然普遍的共识是Foo将默认由隐式默认构造函数(生成的编译器)初始化,但不需要保持为true.

如果Foo没有用户定义的默认构造函数,那么Foo将是未初始化的.更确切地说:Bar或Foo的每个缺少用户定义的默认构造函数的成员都将被编译器生成的Bar的默认构造函数初始化:

class Foo {
   int x;
public:
   void dump() { std::cout << x << std::endl; }
   void set() { x = 5; }
};
class Bar {
   Foo x;
public:
   void dump() { x.dump(); }
   void set() { x.set(); } 
};
class Bar2
{
   Foo x;
public:
   Bar2() : Foo() {}
   void dump() { x.dump(); }
   void set() { x.set(); }
};
template <typename T>
void test_internal() {
   T x;
   x.dump();
   x.set();
   x.dump();
}
template <typename T>
void test() {
   test_internal<T>();
   test_internal<T>();
}
int main()
{
   test<Foo>(); // prints ??, 5, 5, 5, where ?? is a random number, possibly 0
   test<Bar>(); // prints ??, 5, 5, 5
   test<Bar2>(); // prints 0, 5, 0, 5
}
Run Code Online (Sandbox Code Playgroud)

现在,如果Foo有一个用户定义的构造函数,那么它将始终被初始化,无论Bar是否具有用户初始化构造函数.如果Bar有一个用户定义的构造函数,它显式调用Foo的(可能是隐式定义的)构造函数,那么Foo实际上将被初始化.如果Bar的初始化列表没有调用Foo构造函数,那么它将等同于Bar没有用户定义的构造函数的情况.

测试代码可能需要一些解释.我们感兴趣的是编译器是否在没有实际调用构造函数的用户代码的情况下初始化变量.我们想测试对象是否已初始化.现在,如果我们只是在一个函数中创建一个对象,它可能会碰到一个未被触及并且已经包含零的内存位置.我们希望区分运气和成功,因此我们在函数中定义变量并调用函数两次.在第一次运行中,它将打印内存内容并强制更改.在第二次调用函数时,由于堆栈跟踪相同,变量将保持在完全相同的内存位置.如果它被初始化,它将被设置为0,否则它将保持与完全相同位置的旧变量相同的值.

在每个测试运行中,打印的第一个值是初始化值(如果它实际上已初始化)或该内存位置中的值,在某些情况下恰好为0.第二个值只是表示值的测试令牌手动更改后在内存位置.第三个值来自函数的第二次运行.如果正在初始化变量,它将回退到0.如果对象未初始化,则其内存将保留旧内容.


Dav*_*ley 6

如果可以的话,C++编译器将为每个类生成四个函数,如果不提供它们:默认构造函数,复制构造函数,赋值运算符和析构函数.在C++标准(第12章"特殊功能")中,这些被称为"隐式声明"和"隐式定义".他们将有公共访问权限.

不要在构造函数中混淆"隐式定义"和"默认".默认构造函数是可以在没有任何参数的情况下调用的构造函数(如果有的话).如果不提供构造函数,则将隐式定义默认构造函数.它将为每个基类和数据成员使用默认构造函数.

所以,发生的事情是类Foo有一个隐式定义的默认构造函数,而Bar(它似乎没有用户定义的构造函数)使用它隐式定义的默认构造函数,它调用Foo的默认构造函数.

如果您确实想为Bar编写构造函数,可以在其初始化列表中提及foo,但由于您使用的是默认构造函数,因此实际上并不需要指定它.

请记住,如果您为Foo编写构造函数,编译器将不会自动生成默认构造函数,因此如果需要,您必须指定一个构造函数.因此,如果你把像Foo(int n);到富的定义,并没有明确写入默认构造函数(或Foo();Foo(int n = 0);),你不能在其目前的形式吧,因为它不能使用Foo的默认构造函数.在这种情况下,你必须有一个像Bar(int n = 0): foo(n) {}Bar构造函数初始化Foo的构造函数.(注意,Bar(int n = 0) {foo = n;}或者类似的东西不起作用,因为Bar构造函数会首先尝试初始化foo,这会失败.)