参数和成员变量在构造函数中的用法

Usage of parameter and member variable in constructor

本文关键字:用法 构造函数 成员 变量 参数      更新时间:2023-10-16

在编写类的构造函数时,我经常问自己是否应该使用初始化的成员变量或构造函数参数。这里有两个例子来说明我的意思:

构造函数参数

class Foo {
public:
    Foo(int speed) :
        mSpeed(speed),
        mEntity(speed)
    { }
private:
    int mSpeed;
    Entity mEntity;
}

成员变量

class Foo {
public:
    Foo(int speed) :
        mSpeed(speed),
        mEntity(mSpeed)
    { }
private:
    int mSpeed;
    Entity mEntity;
}

此外,在构造函数主体中使用变量时会出现相同的问题。

构造函数参数

class Foo {
public:
    Foo(int speed) :
        mSpeed(speed)
    {
        mMonster.setSpeed(speed);
    }
private:
    int mSpeed;
    Monster mMonster;
}

成员变量

class Foo {
public:
    Foo(int speed) :
        mSpeed(speed)
    {
        mMonster.setSpeed(mSpeed);
    }
private:
    int mSpeed;
    Monster mMonster;
}

我知道这并不重要(除了一些特殊情况),这就是为什么我宁愿征求对代码设计的评论,而不是什么让它工作,什么不工作。

如果您需要一个特定的问题来处理:什么方法会产生一个漂亮且一致的代码设计,并且一个比另一个有(缺点)优势?

编辑:不要忘记问题的第二部分。构造函数体中的变量呢?

我会使用 Constructor 参数,因为在使用该初始值设定项时,这些初始值设定项的执行顺序由声明成员的顺序决定,而不是它们的列出顺序。 所以,在这里要小心。

我个人更喜欢使用构造函数参数,以避免使用尚未初始化的成员变量。

事实上,在这个例子中:

class Foo {
private:
    int mEntity;
    int mSpeed;
public:
    Foo(int speed) :
        mSpeed(speed),
        mEntity(mSpeed)
    { }
}

mEntity 的初始化将在 mSpeed 初始化之前进行(因为它是在之前声明的)。因此,您将使用未初始化的 mSpeed 初始化 mEntity。

--

在构造函数

主体本身内部,我也会使用构造函数参数,因为在调试时看到您使用速度来初始化 mMonster 而不是本身用速度初始化的 mSpeed 会更直接一些。当然,这是一个简约的开销,但由于我们可以轻松避免它,我认为最好这样做。

我更喜欢在必须固定参数的情况下使用成员变量:

class Foo {
public:
    Foo(int speed) :
        mSpeed((speed < 0 ? 0 : speed)),
        mEntity(mSpeed)
    { }
}

这样,如果参数无效,则不会用于导致后续成员也无效。

否则,我坚持使用参数变量。

我会使用构造函数参数。为什么?因为这个问题。构造器参数清晰易读,您无需了解太多C++即可知道会发生什么。如果您对C++了解不够,使用成员很容易出错,并且即使您做得对,也会使团队中没有您知识水平的其他人感到困惑。

如有疑问,请保持简单。

你绝对应该使用构造函数参数。如前所述,成员变量将按照它们在头文件中声明的顺序进行初始化,而不是按照它们在初始化列表中出现的顺序进行初始化。

如果顺序不匹配,一些编译器会警告您,但使用构造函数参数只会让您少担心一件事。例如,在编辑类界面时,很容易以这种方式引入错误。使用成员变量初始化其他成员变量没有任何好处。

我也会使用构造函数参数。请参阅简单示例:

// foo.h
class Foo
{
    std::unique_ptr<int[]> mBuff;
    int mSize;
public:
explicit    Foo(int size);
   // other methods...
};
// foo.c
Foo::Foo(int size)
  : mSize(size) 
  , mBuff( std::make_unique<int[]>(size) ) // here using mSize is wrong, 
            // because, mSize is not initialized yet.
            // here mSize initialized after mBuff, because it's declarated after mBuff member.
{}

因此,如果您使用成员而不是构造函数参数,则可能很容易创建错误情况。