OOP - 抽象类类型,初始化基类和派生类中的变量

时间:2018-04-15 13:21:20

标签: c++ inheritance abstract-class

类似于:How can I initialize base class member variables in derived class constructor?,但我想知道为什么我有:

class A {
public:
    A(int val);
    virtual int get_val() = 0;
protected:
    int val;
};

class B : public A {
public:
    B(int val, int extra);
    int get_val() = 0;
private:
    int extra;
};

我想知道这样做有什么区别:

A::A(int val) : val(val) {}

A::A(int val) {val = val;}

还有为什么,当我在B类的构造函数中时,我不能这样做:

B::B(int b, int extra) : A(b) {
    extra = extra;
}

但我能做到:

B::B(int b, int extra) : A(b) {
    this->extra = extra;
}

,或者

B::B(int b, int extra) : A(b), extra(extra){}

将额外值存储在B中。如果我不这样做,则不存储它。我很困惑正在发生的事情。

2 个答案:

答案 0 :(得分:4)

  

我想知道这样做有什么区别:

A::A(int val) : val(val) {}
     

A::A(int val) {val = val;}

第一个是对的,第二个是错的。

更准确地说,第一个使用构造函数参数A::val的值初始化数据成员val,这毫无疑问正是您打算做什么。

相反,第二个对A::val没有任何作用,只留下未初始化的值,一旦你尝试从数据成员读取,它将在以后导致未定义的行为。 val = val;行将构造函数参数val分配给自身,这完全没有意义。

如果您使用不同的参数名称来消除歧义,那么第二个就可以了,例如:

A::A(int new_val) { val = new_val; }

如果您喜欢自己的this->extra = extra;示例:

,它也可以正常工作
A::A(int val) { this->val = val; }

在这两种情况下,编译器现在都知道您的意思是A::val

然而,这种形式的构造函数实现在C ++中是非典型的,并且通常是Java或C#程序员的标志。它使A::val保持未初始化状态,然后为其赋值。这不是很合乎逻辑。如果可以,为什么不立即初始化它?它也不会与const成员,参考成员或没有默认构造函数的数据类型或以后分配内容的方式一起工作。

顺便说一下,这与效率无关,只与正确性和可读性有关。

答案 1 :(得分:1)

  

我想知道这样做有什么区别:

     

A::A(int val) : val(val) {}

     

     

A::A(int val) {val = val;}

原始类型没有区别。但是,如果val是非基本类型,例如std :: string,使用第一种方式(初始化列表)更有效。想想

方法1与:

相同
string val(val);

方法2与:

相同
string val; //default initialize first;
val = val2; //assign val2 to val

也就是说,即使您没有在初始化列表中提供任何内容,编译器仍然会在进入{}块之前调用默认构造函数来初始化它。由于原始类型没有构造函数,因此使用初始化列表并不能真正提高效率。

  

还有,为什么,当我在B级的构造函数中时,我无法做到:

     

B::B(int b, int extra) : A(b) {

     

extra = extra;

     

}

类似于上面的解释。在{}内,"额外"将被定义,并且本地对象掩盖了数据成员。但是,选择不同的参数名称没有任何害处。