【问题标题】:Bad practice to call base methods in derived constructors?在派生构造函数中调用基方法的坏习惯?
【发布时间】:2011-12-28 08:38:00
【问题描述】:

我只是想知道设置继承成员的最有效方法是以及以下代码是否可以使用:

这是基类的声明:

class cEntity{
private:
    int X, Y;
    int Height, Width;
public:
    cEntity();
    cEntity(int x,int y,int h,int w);
    ~cEntity();

    void setX(int x){X=x;};
    void setY(int y){Y=y;};
    void setCoords(int x, int y){X=x;Y=y;};

    void setHeight(int h){Height = h;};
    void setWidth(int w){Width = w;};
    void setArea(int h, int w){Height=h;Width=w;};

    int getX(){return X;};
    int getY(){return Y;};
    //void getXY(int,int);

    int getHeight(){return Height;};
    int getWidth(){return Width;};
    //void getArea(int,int);
};

这里是派生类的构造函数:

cOrganism::cOrganism () {
    setCoords(0,0);
    setArea(0,0);
    Name = "UNKNOWN";
    Health = 100;
    MaxHealth = 100;
    HealthHiRange =100;
    HealthLoRange = 100;
};

所以。在派生类的构造函数中调用setCoords()和setArea()可以吗?

【问题讨论】:

  • 不,这不是坏习惯。不好的做法是[从派生构造函数调用虚拟方法][1]。 [1]:stackoverflow.com/questions/496440/…
  • @carleeto:从构造函数调用虚方法在 C++ 中完全没问题。这在 Java 中很危险。在 C++ 中,它在正确的程序中是安全且明确定义的。

标签: c++ oop class methods constructor


【解决方案1】:

没关系,但你可以通过调用基础构造函数做得更好:

cOrganism::cOrganism() : cEntity(0, 0, 0, 0) {
  // other stuff
}

事实上,您应该以同样的方式初始化新的派生成员:

cOrganism::cOrganism()
: cEntity(0, 0, 0, 0),
  Name("UNKNOWN"),
  Health(100),
  ...
{
}

(您可能还想阅读一些有关通用 C++ 类设计的内容:如果您将 getter 和 setter 暴露给所有私有变量,那么有些事情不太正确。一个类应该封装 一个模型,而您所做的基本上相反。但这不是技术错误。)

【讨论】:

  • 在这种情况下如何设置基本构造函数参数:cOrganism::cOrganism() : cEntity(0, 0, 0, 0) 如在我的代码中创建对象时的语法是什么样的?
  • 什么意思?您正在调用基本构造函数的四参数版本,我假设它将设置 X、Y、Height 和 Width。当然,您还必须正确实现 that 构造函数。您只需使用默认构造函数创建派生对象:cOrganism jim;
  • 你想要传递给构造函数的任何参数都必须是该构造函数的参数...
  • 我明白,但是当我创建这样的对象时:cOrganism org3(h, mh, hh, lh, n); 我将如何设置基本构造函数的变量?语法如何变化?
  • 哦。只需为派生类添加一个适当的构造函数:cOrganism(int a, int b, int c, int d, std::string name) : cEntity(a, b, c, d), Name(name), Health(50) { }
【解决方案2】:

最好这样称呼它:

cOrganism::cOrganism () : cEntity(0,0,0,0) {
  Name = "UNKNOWN";
  Health = 100;
  MaxHealth = 100;
  HealthHiRange =100;
  HealthLoRange = 100;
}

甚至更好:

cOrganism::cOrganism ()
 : cEntity(0,0,0,0), Name("UNKNOWN"), Health(100), 
   MaxHealth(100), HealthHiRange(100), HealthLoRange(100)
{}

这样,基类成员就被设置为基类实现被构造了。

【讨论】:

  • 看来我总是比@Kerrek SB 落后一步......诅咒你! :)
【解决方案3】:

如果基类的默认构造函数已经将其初始化为合适的值,则不必全部执行。

否则,好的解决方案如下所示。

class A
{
int x;
public:
    A( int xin) :x(xin) {}
};


class B : public A
{
int y;
public:
    B( int xin , int yin ) :A(xin) , y(yin) {}
};

注意B构造函数中的A(xin)。这将调用将 xin 传递给 A 构造函数。

如果你有类似整数的东西,那么你做什么并不重要。但是如果 A::X 实际上是一个重量级的对象。使用您的方法 A::x 将使用默认构造函数构造一次,然后在从派生类构造函数调用 setCoords() 时再次分配。我的解决方案将确保 A::x* 仅构造一次,并且其参数的所有正确值也是如此。

More details here

【讨论】:

    猜你喜欢
    • 2011-03-05
    • 2018-07-21
    • 1970-01-01
    • 2016-07-19
    • 2022-12-03
    • 2018-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多