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

时间:2012-10-17 04:33:37

标签: c++ constructor class-members object-construction

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

在StackOverflow上,我似乎能够找到对象成员变量的其他示例,但通常会立即调用构造函数,如下所示:

class MyClass {
    public:
        MyClass(int n);
    private:
        AnotherClass another(100); // this constructs 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

我使用正确的方法但语法错误吗?或者我应该从另一个方向来看这个?

5 个答案:

答案 0 :(得分:78)

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

BigMommaClass {
    BigMommaClass(int, int);

private:
    ThingOne thingOne;
    ThingTwo thingTwo;
};

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

答案 1 :(得分:27)

您正在尝试使用ThingOne创建operator=,这不会起作用(语法不正确)。此外,您使用类名作为变量名,即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))
{ }

答案 2 :(得分:8)

这个问题有点陈旧,但这是c ++ 11中的另一种方式"做更多工作"在初始化成员变量之前在构造函数中:

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

将调用上面的lambda函数,并将结果传递给thingOnes构造函数。你当然可以将lambda变得如你所愿那样复杂。

答案 3 :(得分:1)

我知道这是5年后的事,但是以上答复并未解决您的软件出了什么问题。 (Yuushi做的很好,但是直到我键入此字时,我才意识到-哎呀!)。他们在标题中回答了问题如何在构造函数中初始化C ++对象成员变量??这与其他问题有关:我使用的方法正确但语法错误吗?还是我应该从另一个方向出发?

编程风格在很大程度上是一个问题,但是在构造函数中尽可能多地执行的另一种观点是使构造函数的数量降至最低,通常具有单独的初始化函数。无需尝试将所有初始化都塞入构造函数中,不必介意有时将某些事情强加到构造函数初始化列表中。

那么,到目前为止,您的软件出了什么问题?

import os
f = 'TRIAL_20134_75690_TOTAL_2018-08-12-17-18.csv'
os.rename(f, f[:f.rindex('_'] + '.csv')

请注意,在这些行之后,private: ThingOne* ThingOne; ThingTwo* ThingTwo; (和ThingOne)现在根据上下文具有两种含义。

在BigMommaClass之外,ThingTwo是您使用ThingOne创建的类<​​/ p>

在BigMommaClass内部,#include "ThingOne.h"是一个指针。

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

后来,当你写

ThingOne

请记住,在this->ThingOne = ThingOne(100); this->ThingTwo = ThingTwo(numba1, numba2); 内部,BigMommaClass是一个指针。

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

ThingOne

然后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!) 有了它,我可以将以下几行添加到我的c ++程序中,并且可以很好地编译。

this->

当你写

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); 来更改编译器对标识符的解释。

答案 4 :(得分:1)

我(也有其他人提到)意识到这个问题很久了,但是我想针对 @chris ,他提出了一种解决方案,该方案将班级成员保留为“ 真正的复合体”成员(即- 指针或NOR 引用)。 注释有点大,因此我将在此处通过一些示例代码进行演示。

当您选择担任我提到的成员时,您还必须牢记以下两点:

1)对于每个没有具有默认ctor的“组成对象”,您必须 ALL 的初始化列表中对其进行初始化如果有多个父类,则为“父亲”类的ctor(即原始示例中的BigMommaClassMyClass和下面的代码中的MyClass)(请参见InnerClass1在下面的示例中)。意味着,只有启用了m_innerClass1(a)默认ctor,您才能“注释” m_innerClass1(15)InnerClass1

2)对于默认值的每个“组成对象”,您 MAY 都可以在初始化列表中对其进行初始化,但是如果您选择不这样做,它也可以使用(请参见下面的示例中的InnerClass2)。

请参阅示例代码(在具有g++版本7.3.0的Ubuntu 18.04中进行了编译):

#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;
}