如何在构造函数中初始化 C++ 对象成员变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12927169/
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
How can I initialize C++ object member variables in the constructor?
提问by Logical Fallacy
I've got a class that has a couple of objects as member variables. I don't want the constructors for these members to be called when declared, so I'm trying to hang onto a pointer to the object explicitly. I have no idea what I'm doing. o_O
我有一个类,它有几个对象作为成员变量。我不希望在声明时调用这些成员的构造函数,因此我试图明确地挂起指向该对象的指针。我不知道我在做什么。o_o
On StackOverflow, I seem to be able to find other examples of object member variables, but usually the constructor is called immediately, like this:
在StackOverflow上,我似乎可以找到其他对象成员变量的例子,但通常构造函数是立即调用的,像这样:
class MyClass {
public:
MyClass(int n);
private:
AnotherClass another(100); // this constructs AnotherClass right away!
};
But I want the MyClass
constructor to call the AnotherClass
constructor. Here's what my code looks like:
但我希望MyClass
构造函数调用AnotherClass
构造函数。这是我的代码的样子:
BigMommaClass.h
BigMommaClass.h
#include "ThingOne.h"
#include "ThingTwo.h"
class BigMommaClass {
public:
BigMommaClass(int numba1, int numba2);
private:
ThingOne* ThingOne;
ThingTwo* ThingTwo;
};
BigMommaClass.cpp
BigMommaClass.cpp
#include "BigMommaClass.h"
BigMommaClass::BigMommaClass(int numba1, int numba2) {
this->ThingOne = ThingOne(100);
this->ThingTwo = ThingTwo(numba1, numba2);
}
Here's the error I'm getting when I try to compile:
这是我尝试编译时遇到的错误:
g++ -Wall -c -Iclasses -o objects/BigMommaClass.o classes/BigMommaClass.cpp
In file included from classes/BigMommaClass.cpp:1:0:
classes/BigMommaClass.h:12:8: error: declaration of aThingTwo* BigMommaClass::ThingTwoa
classes/ThingTwo.h:1:11: error: changes meaning of aThingTwoa from aclass ThingTwoa
classes/BigMommaClass.cpp: In constructor aBigMommaClass::BigMommaClass(int, int)a:
classes/BigMommaClass.cpp:4:30: error: cannot convert aThingOnea to aThingOne*a in assignment
classes/BigMommaClass.cpp:5:37: error: a((BigMommaClass*)this)->BigMommaClass::ThingTwoa cannot be used as a function
make: *** [BigMommaClass.o] Error 1
Am I using the right approach but the wrong syntax? Or should I be coming at this from a different direction?
我是否使用了正确的方法但使用了错误的语法?还是我应该从不同的方向来?
回答by chris
You can specify how to initialize members in the member initializer list:
您可以在成员初始值设定项列表中指定如何初始化成员:
BigMommaClass {
BigMommaClass(int, int);
private:
ThingOne thingOne;
ThingTwo thingTwo;
};
BigMommaClass::BigMommaClass(int numba1, int numba2)
: thingOne(numba1 + numba2), thingTwo(numba1, numba2) {}
回答by Yuushi
You're trying to create a ThingOne
by using operator=
which isn't going to work (incorrect syntax). Also, you're using a class name as a variable name, that is, ThingOne* ThingOne
. Firstly, let's fix the variable names:
您正在尝试ThingOne
使用operator=
which来创建 a将不起作用(语法错误)。此外,您使用类名作为变量名,即ThingOne* ThingOne
. 首先,让我们修复变量名称:
private:
ThingOne* t1;
ThingTwo* t2;
Since these are pointers, they must point to something. If the object hasn't been constructed yet, you'll need to do so explicitly with new in your BigMommaClass
constructor:
由于这些是指针,它们必须指向某些东西。如果尚未构造对象,则需要在BigMommaClass
构造函数中使用 new 显式执行此操作:
BigMommaClass::BigMommaClass(int n1, int n2)
{
t1 = new ThingOne(100);
t2 = new ThingTwo(n1, n2);
}
Generally initializer lists are preferred for construction however, so it will look like:
然而,通常初始化列表更适合构造,所以它看起来像:
BigMommaClass::BigMommaClass(int n1, int n2)
: t1(new ThingOne(100)), t2(new ThingTwo(n1, n2))
{ }
回答by patmanpato
This question is a bit old, but here's another way in c++11 of "doing more work" in the constructor before initialising your member variables:
这个问题有点老了,但这是 C++11 中在初始化成员变量之前在构造函数中“做更多工作”的另一种方法:
BigMommaClass::BigMommaClass(int numba1, int numba2)
: thingOne([](int n1, int n2){return n1+n2;}(numba1,numba2)),
thingTwo(numba1, numba2) {}
The lambda function above will be invoked and the result passed to thingOnes constructor. You can of course make the lambda as complex as you like.
上面的 lambda 函数将被调用,并将结果传递给 thingOnes 构造函数。您当然可以根据需要使 lambda 变得复杂。
回答by Ivan
I know this is 5 years later, but the replies above don't address what was wrong with your software. (Well Yuushi's does, but I didn't realise until I had typed this - doh!). They answer the question in the title How can I initialize C++ object member variables in the constructor?This is about the other questions: Am I using the right approach but the wrong syntax? Or should I be coming at this from a different direction?
我知道这是 5 年后的事,但上面的答复并没有说明您的软件出了什么问题。(嗯,Yuushi 的确实如此,但直到我输入这个我才意识到 - 哦!)。他们回答标题中的问题如何在构造函数中初始化 C++ 对象成员变量?这是关于其他问题:我是否使用了正确的方法但使用了错误的语法?还是我应该从不同的方向来?
Programming style is largely a matter of opinion, but an alternative view to doing as much as possible in a constructor is to keep constructors down to a bare minimum, often having a separate initialization function. There is no need to try to cram all initialization into a constructor, never mind trying to force things at times into the constructors initialization list.
编程风格在很大程度上取决于意见,但在构造函数中尽可能多做的另一种观点是将构造函数保持在最低限度,通常具有单独的初始化函数。没有必要尝试将所有初始化都塞进构造函数中,更不用说有时尝试将某些东西强制放入构造函数初始化列表中。
So, to the point, what was wrong with your software?
那么,说到点子上,你的软件出了什么问题?
private:
ThingOne* ThingOne;
ThingTwo* ThingTwo;
Note that after these lines, ThingOne
(and ThingTwo
) now have two meanings, depending on context.
请注意,在这些行之后,ThingOne
(和ThingTwo
) 现在有两个含义,具体取决于上下文。
Outside of BigMommaClass, ThingOne
is the class you created with #include "ThingOne.h"
在 BigMommaClass 之外,ThingOne
是您创建的类#include "ThingOne.h"
Inside BigMommaClass, ThingOne
is a pointer.
BigMommaClass 内部ThingOne
是一个指针。
That is assuming the compiler can even make sense of the lines and doesn't get stuck in a loop thinking thatThingOne
is a pointer to something which is itself a pointer to something which is a pointer to ...
那是假设编译器甚至可以理解这些行并且不会陷入循环,认为这ThingOne
是一个指向某事物的指针,而该指针本身就是指向某事物的指针,而该指针又是指向...
Later, when you write
以后写的时候
this->ThingOne = ThingOne(100);
this->ThingTwo = ThingTwo(numba1, numba2);
bear in mind that inside of BigMommaClass
your ThingOne
is a pointer.
请记住,BigMommaClass
您的内部ThingOne
是一个指针。
If you change the declarations of the pointers to include a prefix (p)
如果您更改指针的声明以包含前缀 (p)
private:
ThingOne* pThingOne;
ThingTwo* pThingTwo;
Then ThingOne
will always refer to the class and pThingOne
to the pointer.
然后ThingOne
将始终引用类和pThingOne
指针。
It is then possible to rewrite
然后可以重写
this->ThingOne = ThingOne(100);
this->ThingTwo = ThingTwo(numba1, numba2);
as
作为
pThingOne = new ThingOne(100);
pThingTwo = new ThingTwo(numba1, numba2);
which corrects two problems: the double meaning problem, and the missing new
. (You can leave this->
if you like!)
With that in place, I can add the following lines to a c++ program of mine and it compiles nicely.
它纠正了两个问题:双重含义问题和缺失的new
. (this->
如果你愿意,你可以离开!)有了这些,我可以将以下几行添加到我的 C++ 程序中,它编译得很好。
class ThingOne{public:ThingOne(int n){};};
class ThingTwo{public:ThingTwo(int x, int y){};};
class BigMommaClass {
public:
BigMommaClass(int numba1, int numba2);
private:
ThingOne* pThingOne;
ThingTwo* pThingTwo;
};
BigMommaClass::BigMommaClass(int numba1, int numba2)
{
pThingOne = new ThingOne(numba1 + numba2);
pThingTwo = new ThingTwo(numba1, numba2);
};
When you wrote
当你写
this->ThingOne = ThingOne(100);
this->ThingTwo = ThingTwo(numba1, numba2);
the use of this->
tells the compiler that the left hand side ThingOne
is intended to mean the pointer. However we are inside BigMommaClass
at the time and it's not necessary.
The problem is with the right hand side of the equals where ThingOne
is intended to mean the class. So another way to rectify your problems would have been to write
的使用this->
告诉编译器左侧ThingOne
是指指针。但是我们BigMommaClass
当时在里面,没有必要。问题在于等号的右侧,其ThingOne
意在表示班级。所以另一种纠正你的问题的方法是写
this->ThingOne = new ::ThingOne(100);
this->ThingTwo = new ::ThingTwo(numba1, numba2);
or simply
或者干脆
ThingOne = new ::ThingOne(100);
ThingTwo = new ::ThingTwo(numba1, numba2);
using ::
to change the compiler's interpretation of the identifier.
通过::
改变标识的编译器的解释。
回答by Guy Avraham
I'm (also, as others mentioned) aware to the fact that this question is old, yet I wanted to point something regarding the first (and great) answer from @chriswho proposed a solution to the situation where the class members are held as a "true composite" members (i.e.- NOTas pointersNOR references). The note is a bit large so I will demonstrate it here with some sample code.
我(也正如其他人提到的那样)意识到这个问题已经过时了,但我想指出一些关于@chris的第一个(也是很棒的)答案的问题,他提出了解决班级成员被关押的情况的解决方案作为“真正的复合”成员(即,不是作为指针NOR引用)。该注释有点大,因此我将在此处使用一些示例代码进行演示。
When you chose to hold the members as I mentioned, you have to keep in mind also these two things:
当你像我提到的那样选择持有成员时,你还必须记住这两件事:
1) For every "composed object" that DOES NOThave a default ctor - you MUSTinitialize it in the initialization list of ALLthe ctor's of the "father" class (i.e.- BigMommaClass
or MyClass
in the original examples and MyClass
in the code below), in case there are several (see InnerClass1
in the example below). Meaning, you can "comment out" the m_innerClass1(a)
and m_innerClass1(15)
ONLY if you enable the InnerClass1
default ctor.
1)对于每一个“组成的对象”是DOES NOT有一个默认的构造函数-你必须初始化它的初始化列表中所有的构造函数是“爸爸”级(即-的BigMommaClass
或MyClass
在原来的例子,MyClass
在下面的代码),在如果有几个(见InnerClass1
下面的例子)。意思是m_innerClass1(a)
,m_innerClass1(15)
只有启用InnerClass1
默认构造函数,您才能“注释掉”和。
2) For every "composed object" that DOES havea default ctor - you MAYinitialize it within the initialization list, but it will work also if you chose not to (see InnerClass2
in the example below).
2)对于每个具有默认构造函数的“组合对象” -您可以在初始化列表中对其进行初始化,但如果您选择不这样做,它也将起作用(请参见InnerClass2
下面的示例)。
See sample code (complied under Ubuntu 18.04 with g++
version 7.3.0):
查看示例代码(在 Ubuntu 18.04 g++
7.3.0 版本下编译):
#include <iostream>
using namespace std;
class InnerClass1
{
public:
InnerClass1(int a) : m_a(a)
{
cout << "InnerClass1::InnerClass1 - set m_a:" << m_a << endl;
}
/* No default cotr
InnerClass1() : m_a(15)
{
cout << "InnerClass1::InnerClass1() - set m_a:" << m_a << endl;
}
*/
~InnerClass1()
{
cout << "InnerClass1::~InnerClass1" << endl;
}
private:
int m_a;
};
class InnerClass2
{
public:
InnerClass2(int a) : m_a(a)
{
cout << "InnerClass2::InnerClass2 - set m_a:" << m_a << endl;
}
InnerClass2() : m_a(15)
{
cout << "InnerClass2::InnerClass2() - set m_a:" << m_a << endl;
}
~InnerClass2()
{
cout << "InnerClass2::~InnerClass2" << endl;
}
private:
int m_a;
};
class MyClass
{
public:
MyClass(int a, int b) : m_innerClass1(a), /* m_innerClass2(a),*/ m_b(b)
{
cout << "MyClass::MyClass(int b) - set m_b to:" << m_b << endl;
}
MyClass() : m_innerClass1(15), /*m_innerClass2(15),*/ m_b(17)
{
cout << "MyClass::MyClass() - m_b:" << m_b << endl;
}
~MyClass()
{
cout << "MyClass::~MyClass" << endl;
}
private:
InnerClass1 m_innerClass1;
InnerClass2 m_innerClass2;
int m_b;
};
int main(int argc, char** argv)
{
cout << "main - start" << endl;
MyClass obj;
cout << "main - end" << endl;
return 0;
}