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

xpszyzbs  于 2023-05-30  发布在  其他
关注(0)|答案(5)|浏览(268)

我有一个类,它有几个对象作为成员变量。我不希望这些成员的构造函数在声明时被调用,所以我试图显式地挂在指向对象的指针上。我不知道我在做什么。
我想也许我可以这样做,在初始化对象成员变量时立即调用构造函数:

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

我是否使用了正确的方法,但语法错误?或者我应该从另一个Angular 来看待这个问题?

q8l4jmvw

q8l4jmvw1#

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

BigMommaClass {
    BigMommaClass(int, int);

private:
    ThingOne thingOne;
    ThingTwo thingTwo;
};

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

hgc7kmma2#

您试图使用operator=创建一个ThingOne,但这不起作用(语法不正确)。另外,您使用类名作为变量名,即ThingOne* ThingOne。首先,让我们修改变量名:

private:
    ThingOne* t1;
    ThingTwo* t2;

既然这些是指针,它们一定指向某个东西。如果对象还没有被构造,你需要在BigMommaClass构造函数中显式地使用new来构造:

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

63lcw9qa3#

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

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

将调用上面的lambda函数,并将结果传递给thingOnes构造函数。当然,你可以让lambda像你喜欢的那样复杂。

wgmfuz8q

wgmfuz8q4#

我知道这是5年后,但上面的答复并没有解决你的软件有什么问题。(好吧,Yuushi的是,但我没有意识到,直到我打了这个- doh!)。他们回答了标题中的问题**如何在构造函数中初始化C++对象成员变量?这是关于其他问题: 我是否使用了正确的方法,但语法错误?或者我应该从另一个Angular 来看待这个问题?
编程风格在很大程度上是一个观点问题,但是在构造函数中尽可能多地做的另一种观点是将构造函数保持在最低限度,通常具有单独的初始化函数。没有必要把所有的初始化都塞进构造函数中,更不用说有时候强制把东西放到构造函数的初始化列表中。
所以,直接点,你的软件出了什么问题?

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);

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

9bfwbjaz

9bfwbjaz5#

关于chris的第一个(和伟大的)回答,他提出了一个解决方案,解决了类成员被保存为“ 真复合 *”成员的情况(即-不是作为指针也不是引用):
注解有点大,所以我将在这里用一些示例代码来演示它。
当你选择像我提到的那样持有成员时,你必须记住这两件事:
1.对于每个没有默认构造函数的“组合对象”,你必须在“父”类的所有构造函数的初始化列表中初始化它(即原始示例中的-BigMommaClassMyClass和下面代码中的MyClass),以防有几个构造函数(参见下面示例中的InnerClass1)。也就是说,如果启用了InnerClass1默认构造函数,就可以“注解掉”m_innerClass1(a)m_innerClass1(15)only
1.对于每个
默认构造函数的“组合对象”,您可以在初始化列表中初始化它,但如果您选择不这样做,它也会工作(参见下面示例中的InnerClass2)。
参见示例代码(在Ubuntu 18.04(Bionic Beaver)下编译,g++版本7.3.0):

#include <iostream>

class InnerClass1
{
    public:
        InnerClass1(int a) : m_a(a)
        {
            std::cout << "InnerClass1::InnerClass1 - set m_a:" << m_a << '\n';
        }

        /* No default constructor
        InnerClass1() : m_a(15)
        {
            std::cout << "InnerClass1::InnerClass1() - set m_a:" << m_a << '\n';
        }
        */

        ~InnerClass1()
        {
            std::cout << "InnerClass1::~InnerClass1" << '\n';
        }

    private:
        int m_a;
};

class InnerClass2
{
    public:
        InnerClass2(int a) : m_a(a)
        {
            std::cout << "InnerClass2::InnerClass2 - set m_a:" << m_a << '\n';
        }

        InnerClass2() : m_a(15)
        {
            std::cout << "InnerClass2::InnerClass2() - set m_a:" << m_a << '\n';
        }

        ~InnerClass2()
        {
            std::cout << "InnerClass2::~InnerClass2" << '\n';
        }

    private:
        int m_a;
};

class MyClass
{
    public:
        MyClass(int a, int b) : m_innerClass1(a), /* m_innerClass2(a),*/ m_b(b)
        {
            std::cout << "MyClass::MyClass(int b) - set m_b to:" << m_b << '\n';
        }

         MyClass() : m_innerClass1(15), /*m_innerClass2(15),*/ m_b(17)
        {
            std::cout << "MyClass::MyClass() - m_b:" << m_b << '\n';
        }

        ~MyClass()
        {
            std::cout << "MyClass::~MyClass" << '\n';
        }

    private:
        InnerClass1 m_innerClass1;
        InnerClass2 m_innerClass2;
        int m_b;
};

int main(int argc, char** argv)
{
    std::cout << "main - start" << '\n';

    MyClass obj;

    std::cout << "main - end" << '\n';
    return 0;
}

相关问题