繁体   English   中英

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

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

我有一个类,它有几个对象作为成员变量。 我不希望在声明时调用这些成员的构造函数,因此我试图明确地挂起指向该对象的指针。 我不知道我在做什么。

我想也许我可以执行以下操作,在初始化对象成员变量时立即调用构造函数:

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

但我希望MyClass构造函数调用AnotherClass构造函数。 这是我的代码的样子:

文件BigMommaClass.h

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

class BigMommaClass {

        public:
                BigMommaClass(int numba1, int numba2);

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

文件BigMommaClass.cpp

#include "BigMommaClass.h"

BigMommaClass::BigMommaClass(int numba1, int numba2) {
        this->ThingOne = ThingOne(100);
        this->ThingTwo = ThingTwo(numba1, numba2);
}

这是我尝试编译时遇到的错误:

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

我是否使用了正确的方法,但使用了错误的语法? 还是我应该从不同的方向来?

您可以在成员初始值设定项列表中指定如何初始化成员:

BigMommaClass {
    BigMommaClass(int, int);

private:
    ThingOne thingOne;
    ThingTwo thingTwo;
};

BigMommaClass::BigMommaClass(int numba1, int numba2)
    : thingOne(numba1 + numba2), thingTwo(numba1, numba2) {}

您正在尝试使用operator=创建ThingOne ,这将不起作用(语法不正确)。 此外,您使用类名作为变量名,即ThingOne* ThingOne 首先,让我们修复变量名称:

private:
    ThingOne* t1;
    ThingTwo* t2;

由于这些是指针,它们必须指向某些东西。 如果尚未构造对象,则需要在BigMommaClass构造函数中使用 new 显式执行此BigMommaClass

BigMommaClass::BigMommaClass(int n1, int n2)
{
    t1 = new ThingOne(100);
    t2 = new ThingTwo(n1, n2);
}

然而,通常初始化列表更适合构造,所以它看起来像:

BigMommaClass::BigMommaClass(int n1, int n2)
    : t1(new ThingOne(100)), t2(new ThingTwo(n1, n2))
{ }

这个问题有点老了,但这是 C++11 中在初始化成员变量之前在构造函数中“做更多工作”的另一种方法:

BigMommaClass::BigMommaClass(int numba1, int numba2)
    : thingOne([](int n1, int n2){return n1+n2;}(numba1,numba2)),
      thingTwo(numba1, numba2) {}

上面的 lambda 函数将被调用并将结果传递给 thingOnes 构造函数。 您当然可以根据需要使 lambda 变得复杂。

我知道这是 5 年后的事,但上面的答复并没有说明您的软件出了什么问题。 (嗯,Yuushi 的确实如此,但直到我输入这个我才意识到 - 哦!)。 他们回答标题中的问题如何在构造函数中初始化 C++ 对象成员变量? 这是关于其他问题:我是否使用了正确的方法但使用了错误的语法? 还是我应该从不同的方向来?

编程风格在很大程度上取决于意见,但在构造函数中尽可能多做的另一种观点是将构造函数保持在最低限度,通常具有单独的初始化函数。 没有必要尝试将所有初始化都塞进构造函数中,更不用说有时尝试将某些东西强制放入构造函数初始化列表中。

那么,说到点子上,你的软件出了什么问题?

private:
    ThingOne* ThingOne;
    ThingTwo* ThingTwo;

请注意,在这些行之后, ThingOne (和ThingTwo )现在有两个含义,具体取决于上下文。

在 BigMommaClass 之外, ThingOne是您使用#include "ThingOne.h"创建的类

在 BigMommaClass 中, ThingOne是一个指针。

那是假设编译器甚至可以理解这些行,并且不会陷入循环,认为ThingOne是指向某事物的指针,而该指针本身是指向某事物的指针,而该指针是指向 ...

以后写的时候

this->ThingOne = ThingOne(100);
this->ThingTwo = ThingTwo(numba1, numba2);

请记住,在BigMommaClass内部,您的ThingOne是一个指针。

如果您更改指针的声明以包含前缀 (p)

private:
    ThingOne* pThingOne;
    ThingTwo* pThingTwo;

然后ThingOne总是引用类和pThingOne指针。

然后可以重写

this->ThingOne = ThingOne(100);
this->ThingTwo = ThingTwo(numba1, numba2);

作为

pThingOne = new ThingOne(100);
pThingTwo = new ThingTwo(numba1, numba2);

这纠正了两个问题:双重含义问题和缺少的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);
};

当你写

this->ThingOne = ThingOne(100);
this->ThingTwo = ThingTwo(numba1, numba2);

this->的使用告诉编译器左边的ThingOne是用来表示指针的。 然而,我们当时在BigMommaClass内部,这没有必要。

问题在于等号的右侧,其中ThingOne旨在表示类。 所以另一种纠正你的问题的方法是写

this->ThingOne = new ::ThingOne(100);
this->ThingTwo = new ::ThingTwo(numba1, numba2);

或者干脆

ThingOne = new ::ThingOne(100);
ThingTwo = new ::ThingTwo(numba1, numba2);

使用::来改变编译器对标识符的解释。

关于克里斯的第一个(也是伟大的)答案,他提出了一种解决方案,以解决类成员被视为“真正的复合”成员(即,不是作为指针引用)的情况:

该注释有点大,因此我将在此处使用一些示例代码进行演示。

当你选择我提到的成员时,你还要记住这两件事:

  1. 对于每个没有默认构造函数的“组合对象”-您必须在“父”类的所有构造函数的初始化列表中对其进行初始化(即原始示例中的BigMommaClassMyClass和下面代码中的MyClass ),如果有几个(请参阅下面示例中的InnerClass1 )。 意思是,只有启用InnerClass1默认构造函数时,才能“注释掉” m_innerClass1(a)m_innerClass1(15)

  2. 对于每个具有默认构造函数的“组合对象” - 您可以在初始化列表中对其进行初始化,但如果您选择不这样做,它也可以工作(请参阅下面示例中的InnerClass2 )。

请参阅示例代码(在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