Modern C++ 之面向对象
委托构造函数(Delegate constructor)
C++11引入了
Delegate Constructor
的概念,用于在一个类中让一个构造函数使用另外一个构造函数,从而用来简化初始化的代码
Talk is cheap, show me the code
.下面定义基类Base
,里面含有两个变量并且含有两个构造函数,其中带参数的构造函数会调用不带参的构造函数,完整示例代码如下所示:
class Base
{
public:
int value1;
int value2;
public:
Base()
{
value1 = 1;
}
// 使用Delegete Base方法,用来简化code
Base(int value) :Base()
{
value2 = value;
}
};
构造函数的继承
一个类只能初始化它的的直接基类,也就是说一个类只能继承直接基类的构造函数。类不能继承默认、拷贝和移动构造函数。在传统的C++中,如果一个类要继承基类的构造函数,那么需要将参数一个个传递,效率较低。在C++11中,可以使用
using
声明语句直接继承基类的构造函数
class SubBase :public Base
{
public:
using Base::Base; // 继承构造函数
};
精确地重写虚函数
在传统C++中,很有可能会出现重写虚函数的操作,一个简单的示例代码如下所示:
struct Base {
virtual void foo(int);
};
//
struct SubBase :Base {
void foo(); // overload foo function in Base, or just write a new function
};
从上面的代码中分析可以得知,SubBase
中的foo
有可能是用来重载Base
的foo
函数,又或者是直接新写一个名字相同的函数。但是这样会存在一个问题:如果base
的foo
函数被删除了,那么SubBase
里的foo
函数就不再是重写虚函数了,而是一个普通的函数了,这种问题就很容易迷惑自己。
为了解决上面的迷惑行为,C++11引入了两个关键字override
和final
,用于解决上面所说的问题。
override
如果需要重写一个函数,那么可以使用
override
关键字进行声明,之后编译器会判断父类中是否会有对应的虚函数,没有的话则无法编译通过
示例代码:
struct OverBase
{
virtual void foo(int);
};
struct SubOverBase :OverBase
{
virtual void foo(int) override; //合法声明
//virtual void foo(double) override; 父类中没有对应的函数,所以声明不合法
};
final
final
关键字用来限制类不在被继承或者禁止重载虚函数
struct FinalBase
{
virtual void foo(int) final;
};
struct SubFinalBase1 final :FinalBase // legal statement
{
};
/*
* 非法定义示例
struct SubFinalBase2 :SubFinalBase1 // 非法定义,类使用final关键字限制继承
{
};
struct SubFinalBase3 :FinalBase
{
void foo(int); // 非法顶底,foo函数使用final限制重载
};
*/
精确地使用和删除默认构造函数
在传统C++中,如果用户在程序中没有显示写构造函数,那么编译器会自己生成默认的构造函数、拷贝构造函数和析构函数等,并且也会为所有类定义 new delete
的操作。
但有的时候也会有一些特定的需求,例如精确控制默认构造函数的产生与否。打个比方,当一个类不能被复制的时候,那么类中的拷贝构造函数和一些操作都必须被声明位private
。如果我们尝试去使用这些未定义的方法,那么将会引起错误;
并且,当用户定义了构造函数的时候,那么类的默认构造函数是不会存在的,但是如果我们需要类必须存在一个默认构造,这个时候就非常尴尬,因为两者不能并存啊。
为了解决上面所说的情形,C++11提供了下面的解决办法,具体使用参见示例代码:
class Magic
{
public:
Magic() = default; // 使用默认构造函数
Magic& operator=(const Magic&) = delete; // 拒绝使用
Magic(int magic_number);
};
更强的枚举类型
传统C++中枚举类型不是类型安全的,并且是当作整形来处理的,因此可以将两个不同的枚举类型用来比较大小。并且在不同的枚举类型中,里面的枚举变量名字也不能一样,因为作用域是一样的。C++11引入了
enum class
或者enum struct
来提高枚举类型的使用率。
enum class new_enum : unsigned int
{
value1,
value2,
value3 = 100,
value4 = 100
};