- 禁止继承
在C++11之前,C++没有final关键字,禁止继承的方法大多是利用从虚基类派生的方式。现在final关键字已经被C++11标准收录。
1 2 3 4 5 6 7 8
| class BaseClass final { ... };
class DerivedClass : public BaseClass { };
|
- 禁止重写(override
和禁止继承一样,通过final关键字来实现,禁止重写中final关键字只能用于virtual成员函数。注意这里指的不是overwrite(覆写),overwrite成员函数可以不是虚函数(参数也可以不同)。示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class BaseClass { public: BaseClass(); virtual void someMethod() final; };
class DerivedClass : public BaseClass { public: DerivedClass(); virtual void someMethod(); virtual void someMethod(int i); };
|
- override关键字
同样C++11也引入了大家所期盼的override关键字,用来声明子类重写了基类的某个虚函数。
1 2 3 4 5 6 7 8 9 10 11 12 13
| class BaseClass { public: BaseClass(); virtual void someMethod(int i); };
class DerivedClass : public BaseClass { public: DerivedClass(); virtual void someMethod(int i) override; };
|
个人认为这个关键字主要用于防止基类修改了虚函数的参数列表,而导致子类无意识地创建了一个新的虚函数的行为。
- 继承构造函数
这个比较有意思,C++11之前,子类不能通过基类的构造函数来创建子类的实例,现在,子类通过using声明可以将基类的构造函数声明为可见,从而可以利用和基类相同的构造函数方式来创建自定义的子类形态,这种方法将来或许大有可为,但是也有需要注意的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class BaseClass { public: BaseClass(const std::string& str); BaseClass(double d); };
class DerivedClass : public BaseClass { public: using BaseClass::BaseClass;
DerivedClass(int id) : m_nID(id){ }
private: int m_nID; };
|
这样使用using声明后,就可以使用double参数版本(或是string&类型参数的版本)的基类构造函数来创建子类对象。但是需要面对子类对象成员初始化的问题:
1
| DerivedClass dcFromBaseCtor("Not good");
|
这样构造出的子类对象无法自定义其自身成员变量的初始化,简单的成员变量可以使用声明初始化来解决这个问题,例如int m_nID = 0;
面对复杂的子类,可以在基类中定义一个初始化的虚函数,由子类重写它来实现子类成员的初始化。由于手头边的VS2012编译器目前还不支持继承构造函数,所以无法实践,但是个人认为下面这么写也是符合C++11标准的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class BaseClass { public: BaseClass(std::string& str) { m_baseData = str; Initialize(); }
virtual void Initialize(){}
protected: std::string m_baseData; };
class DerivedClass : public BaseClass { public: using BaseClass::BaseClass;
DerivedClass(int value) :BaseClass(std::string("from dervied")), m_derivedData(value) {}
virtual void Initialize() override { m_derivedData = 0; } int m_derivedData; };
|
这时候使用基类的构造函数来初始化子类对象就更安全了:
1 2
| std::string str("PasstoBaseClass"); DerivedClass dcFromBaseCtor(str);
|