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

OOP - abstract class types, initializing variables in base and derived classes

本文关键字:派生 变量 基类 抽象类 类型 初始化 OOP      更新时间:2023-10-16

类似于: 如何在派生类构造函数中初始化基类成员变量?,但我想知道为什么如果我有:

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 中。如果我不做这些,它就不会存储。我对正在发生的事情感到非常困惑。

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

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

和:

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

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

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

相比之下,第二个对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成员、引用成员或没有默认构造函数或稍后分配某些内容的方法的数据类型一起使用。

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

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

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;

}

与上面的解释类似。在 {} 中,将定义"extra",并且本地对象使数据成员黯然失色。但是,选择不同的参数名称没有害处。