简体   繁体   English

如何在构造函数中初始化 C++ 对象成员变量?

[英]How can I initialize C++ object member variables in the constructor?

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.我不知道我在做什么。

I thought maybe I could do the following, where the constructor is called immediately when initializing the object member variable:我想也许我可以执行以下操作,在初始化对象成员变量时立即调用构造函数:

class MyClass {
    public:
        MyClass(int n);
    private:
        AnotherClass another(100); // Construct AnotherClass right away!
};

But I want the MyClass constructor to call the AnotherClass constructor.但我希望MyClass构造函数调用AnotherClass构造函数。 Here's what my code looks like:这是我的代码的样子:

FIle BigMommaClass.h文件BigMommaClass.h

#include "ThingOne.h"
#include "ThingTwo.h"

class BigMommaClass {

        public:
                BigMommaClass(int numba1, int numba2);

        private:
                ThingOne* ThingOne;
                ThingTwo* ThingTwo;
};

FIle 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 âThingTwo* BigMommaClass::ThingTwoâ
classes/ThingTwo.h:1:11: error: changes meaning of âThingTwoâ from âclass ThingTwoâ
classes/BigMommaClass.cpp: In constructor âBigMommaClass::BigMommaClass(int, int)â:
classes/BigMommaClass.cpp:4:30: error: cannot convert âThingOneâ to âThingOne*â in assignment
classes/BigMommaClass.cpp:5:37: error: â((BigMommaClass*)this)->BigMommaClass::ThingTwoâ 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?还是我应该从不同的方向来?

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) {}

You're trying to create a ThingOne by using operator= which isn't going to work (incorrect syntax).您正在尝试使用operator=创建ThingOne ,这将不起作用(语法不正确)。 Also, you're using a class name as a variable name, that is, ThingOne* ThingOne .此外,您使用类名作为变量名,即ThingOne* ThingOne Firstly, let's fix the variable names:首先,让我们修复变量名称:

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::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))
{ }

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.上面的 lambda 函数将被调用并将结果传递给 thingOnes 构造函数。 You can of course make the lambda as complex as you like.您当然可以根据需要使 lambda 变得复杂。

I know this is 5 years later, but the replies above don't address what was wrong with your software.我知道这是 5 年后的事,但上面的答复并没有说明您的软件出了什么问题。 (Well, Yuushi's does, but I didn't realise until I had typed this - doh!). (嗯,Yuushi 的确实如此,但直到我输入这个我才意识到 - 哦!)。 They answer the question in the title How can I initialize C++ object member variables in the constructor?他们回答标题中的问题如何在构造函数中初始化 C++ 对象成员变量? 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?还是我应该从不同的方向来?

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 that ThingOne 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 .这纠正了两个问题:双重含义问题和缺少的new (You can leave this-> if you like!) (你可以离开this->如果你愿意!)

With that in place, I can add the following lines to a C++ program of mine and it compiles nicely.有了这些,我可以将以下几行添加到我的 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. this->的使用告诉编译器左边的ThingOne是用来表示指针的。 However we are inside BigMommaClass at the time and it's not necessary.然而,我们当时在BigMommaClass内部,这没有必要。

The problem is with the right hand side of the equals where ThingOne is intended to mean the class.问题在于等号的右侧,其中ThingOne旨在表示类。 So another way to rectify your problems would have been to write所以另一种纠正你的问题的方法是写

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.使用::来改变编译器对标识符的解释。

Regarding the first ( and great ) answer from chris who proposed a solution to the situation where the class members are held as a " true composite " members (ie- not as pointers nor references ):关于克里斯的第一个(也是伟大的)答案,他提出了一种解决方案,以解决类成员被视为“真正的复合”成员(即,不是作为指针引用)的情况:

The note is a bit large, so I will demonstrate it here with some sample code.该注释有点大,因此我将在此处使用一些示例代码进行演示。

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 not have a default constructor - you must initialize it in the initialization list of all the constructor's of the "father" class (ie- BigMommaClass or MyClass in the original examples and MyClass in the code below), in case there are several (see InnerClass1 in the example below).对于每个没有默认构造函数的“组合对象”-您必须在“父”类的所有构造函数的初始化列表中对其进行初始化(即原始示例中的BigMommaClassMyClass和下面代码中的MyClass ),如果有几个(请参阅下面示例中的InnerClass1 )。 Meaning, you can "comment out" the m_innerClass1(a) and m_innerClass1(15) only if you enable the InnerClass1 default constructor.意思是,只有启用InnerClass1默认构造函数时,才能“注释掉” m_innerClass1(a)m_innerClass1(15)

  2. For every "composed object" that does have a default constructor - you may initialize it within the initialization list, but it will work also if you chose not to (see InnerClass2 in the example below).对于每个具有默认构造函数的“组合对象” - 您可以在初始化列表中对其进行初始化,但如果您选择不这样做,它也可以工作(请参阅下面示例中的InnerClass2 )。

See sample code (compiled under Ubuntu 18.04 (Bionic Beaver) with g++ version 7.3.0):请参阅示例代码(在Ubuntu 18.04 (Bionic Beaver) 下编译, 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 constructor
        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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM