C++ - 在类中构造对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/849812/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:34:55  来源:igfitidea点击:

C++ - construction of an object inside a class

c++constructoroop

提问by SolarBear

I'm fairly new to C++, and I'm not sure about this one. Have a look at the following example which sums up my current problem.

我对 C++ 相当陌生,我不确定这个。看看下面的例子,它总结了我当前的问题。

class Foo
{
    //stuff
};

class Bar
{
    Foo foo;
};

So Bar constains a full Foo object, not just a reference or pointer. Is this object initialized by its default constructor ? Do I need to explicitly call its constructor, and if so, how and where ?

所以 Bar 包含一个完整的 Foo 对象,而不仅仅是一个引用或指针。此对象是否由其默认构造函数初始化?我是否需要显式调用它的构造函数,如果需要,如何以及在哪里调用?

Thanks.

谢谢。

采纳答案by Frank Schwieterman

It will be initialized by its default constructor. If you want to use a different constructor, you might have something like this:

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

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

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

    Foo foo;
};

回答by David Rodríguez - dribeas

Construction is a fairly hard topic in C++. The simple answer is it depends. Whether Foo is initialized or not depends on the definition of Foo itself. About the second question: how to make Bar initialize Foo: initialization listsare the answer.

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

While general consensus is that Foo will be default initialized by the implicit default constructor (compiler generated), that does not need to hold true.

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

If Foo does not have a user defined default constructor then Foo will be uninitialized. To be more precise: each member of Bar or Foo lacking a user defined default constructor will be uninitialized by the compiler generated default constructor of Bar:

如果 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
}

Now, if Foo had a user defined constructor then it would be initialized always, regardless of whether Bar has or not a user initialized constructor. If Bar has a user defined constructor that explicitly calls the (possibly implicitly defined) constructor of Foo, then Foo will in fact be initialized. If the initialization list of Bar does not call the Foo constructor then it will be equivalent to the case where Bar had no user defined constructor.

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

The test code may need some explaining. We are interested on whether the compiler does initialize the variable without the user code actually calling the constructor. We want to test whether the object is initialized or not. Now if we just create an object in a function it might happen to hit a memory position that was untouched and already contains zeroes. We want to differentiate luck from success, so we define a variable in a function and call the function twice. In the first run, it will print the memory contents and force a change. In the second call to the function, as the stack trace is the same, the variable will be held in exactly the same memory position. If it was initialized, it would be set to 0, else it would keep the same value the old variable in exactly the same position had.

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

In each of the test runs, the first value printed is the initialized value (if it was actually initialized) or the value in that memory position, that in some cases happen to be 0. The second value is just a test token representing the value at the memory position after manually changing it. The third value comes from the second run of the function. If the variable is being initialized it will fall back to 0. If the object is not initialized, its memory will keep the old contents.

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

回答by David Thornley

There are four functions the C++ compiler will generate for each class, if it can, and if you don't provide them: a default constructor, a copy constructor, an assignment operator, and a destructor. In the C++ Standard (chapter 12, "Special Functions"), these are referred to as "implicitly declared" and "implicitly defined". They will have public access.

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

Don't confuse "implicitly-defined" with "default" in a constructor. The default constructor is the one that can be called without any arguments, if there is one. If you provide no constructor, a default one will be implicitly defined. It will use the default constructors for each base class and data member.

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

So, what is happening is that class Foo has an implicitly defined default constructor, and Bar (which doesn't seem to have a user-defined constructor) uses its implicitly defined default constructor which calls Foo's default constructor.

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

If you did want to write a constructor for Bar, you could mention foo in its initializer list, but since you're using the default constructor you don't actually have to specify it.

如果您确实想为 Bar 编写一个构造函数,您可以在其初始值设定项列表中提及 foo,但由于您使用的是默认构造函数,因此您实际上不必指定它。

Remember that, if you do write a constructor for Foo, the compiler will not automatically generate a default constructor, and so you will have to specify one if you need one. Therefore, if you were to put something like Foo(int n);into the definition of Foo, and didn't explicitly write a default constructor (either Foo();or Foo(int n = 0);), you couldn't have a Bar in its present form, since it couldn't use Foo's default constructor. In this case, you'd have to have a constructor like Bar(int n = 0): foo(n) {}having the Bar constructor initialize the Foo. (Note that Bar(int n = 0) {foo = n;}or the like wouldn't work, since the Bar constructor would first try to initialize foo, and that would fail.)

请记住,如果您确实为 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,并且会失败。)

回答by JaredPar

If you do not explicitly call a constructor of foo inside of Bar's constructor then the default one will be used. You can control this by explicitly calling the constructor

如果您没有在 Bar 的构造函数中显式调用 foo 的构造函数,则将使用默认的构造函数。您可以通过显式调用构造函数来控制它

Bar::Bar() : foo(42) {}

This is of course assuming you add a Foo::Foo(int) to the code :)

这当然是假设您在代码中添加了 Foo::Foo(int) :)

回答by Macke

Full object. No, it's default constructed in Bar's default constructor.

完整的对象。不,它是在 Bar 的默认构造函数中默认构造的。

Now, if Foo had a constructor that only took, say, an int. You'd need a constructor in Bar to call Foo's constructor, and say what that is:

现在,如果 Foo 有一个只接受 int 的构造函数。您需要在 Bar 中使用一个构造函数来调用 Foo 的构造函数,并说明它是什么:

class Foo {
public:
    Foo(int x) { .... }
};

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

    Foo foo;
};

But if Foo had a default constructor Foo(), the compiler generates Bar's constructor automatically, and that would call Foo's default (i.e. Foo())

但是如果 Foo 有一个默认的构造函数 Foo(),编译器会自动生成 Bar 的构造函数,这将调用 Foo 的默认构造函数(即 Foo())

回答by Naaff

Unless you specify otherwise, foo is initialized using its default constructor. If you want to use some other constructor, you need to do so in the initializer list for Bar:

除非您另外指定,否则 foo 将使用其默认构造函数进行初始化。如果你想使用其他的构造函数,你需要在 Bar 的初始化列表中这样做:

Bar::Bar( int baz ) : foo( baz )
{
    // Rest of the code for Bar::Bar( int ) goes here...
}

回答by user6882413

Constructor meant for setting an initial state of object. In case of inheritance hierarchy, base class objects will be constructed in the order of inheritance hierarchy (IS-A relation in OO terminology) followed by derived class objects.

用于设置对象初始状态的构造函数。在继承层次结构的情况下,基类对象将按照继承层次结构(OO 术语中的 IS-A 关系)的顺序构造,然后是派生类对象。

Similarly when an object is embedded in another object (HAS-A relation in OO terms or containment), constructors of embedded object are called in the order of their declaration.

类似地,当一个对象嵌入到另一个对象中时(OO 术语中的 HAS-A 关系或包含),嵌入对象的构造函数按其声明的顺序被调用。

The compiler parses all the members of the class B, and then generates the code for each method. At that point, it knows all the members and their order, and it'll construct the members in order, using the default constructors unless otherwise specified. So foo is constructed without calling explicitly its default constructor. What you need to do is just create object of Bar.

编译器解析类 B 的所有成员,然后为每个方法生成代码。那时,它知道所有成员及其顺序,并且将按顺序构造成员,除非另有说明,否则使用默认构造函数。所以 foo 是在没有显式调用其默认构造函数的情况下构造的。您需要做的只是创建 Bar 的对象。

回答by dirkgently

So Bar constains a full Foo object, not just a reference or pointer. Is this object initialized by its default constructor?

所以 Bar 包含一个完整的 Foo 对象,而不仅仅是一个引用或指针。该对象是否由其默认构造函数初始化?

If Foohas a default ctor, an object of type Foowill be using the default ctor when you create an object of type Bar. Otherwise, you need to call the Fooctor yourself or your Bar's ctor will make your compiler complain loduly.

如果Foo具有默认构造函数,Foo则在创建类型为 的对象时,类型的对象将使用默认构造函数Bar。否则,您需要自己调用Fooctor,否则您Bar的 ctor 会使您的编译器大声抱怨。

E.g:

例如:

class Foo {
public:
 Foo(double x) {}
};

class Bar  {
 Foo x;
};

int main() {
 Bar b;
}

The above will have the compiler complain something like:

以上将使编译器抱怨如下:

"In constructor 'Bar::Bar()': Line 5: error: no matching function for call to 'Foo::Foo()'

Do I need to explicitly call its constructor, and if so, how and where ?

“在构造函数 'Bar::Bar()' 中:第 5 行:错误:没有匹配的函数用于调用 'Foo::Foo()'

我是否需要显式调用它的构造函数,如果需要,如何以及在哪里调用?

Modify the above example as follows:

修改上面的例子如下:

class Foo {
 public:
  Foo(double x) {} // non-trivial ctor
};

class Bar  {     
 Foo x;
public:
  Bar() : x(42.0) {} // non-default ctor, so public access specifier required
};

int main() {
 Bar b;
}

回答by Shane C. Mason

You do not need to call the default contructor explicitly in C++, it will be called for you. If you wanted to call a different contructor, you could do this:

您不需要在 C++ 中显式调用默认构造函数,它会为您调用。如果你想调用不同的构造函数,你可以这样做:

Foo foo(somearg)