override声明的作用很简单,就是当你为子类改写从父类那里继承下来的成员函数时,如果因为各种原因,导致改写失败(失败原因有很多,例如形参类型错误、函数修饰词遗漏等等),将在编译时给你明确提示。
与override相对应的时final关键字,final有两个作用,分别为:
- 当final修饰的是基类的虚函数时,表明改虚函数禁止在子类中被改写
- 当final修饰的是一个类时,表示该类被禁止作为基类
下面再介绍一个知识点,就是引用修饰词。
我们这里假设有个Widget类,且类中有个std::vector型别的成员变量,我们提供了一个访问器函数data(),让外部客户可以直接通过该函数,访问该成员变量,示例代码如下:
class Widget {
public:
std::vector<int>& data() {
return values;
}
private:
std::vector<int> values;
}
此时,客户的调用代码可能为:
Widget w;
auto val = w.data();
此时,data()返回的是左值引用,所以val将会通过复制的方式,将w中的values变量内容拷贝过去,这并没有什么问题。
若客户有个函数makeWidget()函数用于创造Widget的实例,客户的代码很可能变为:
auto val2 = makeWidget().data();
此时,我们知道因为data()返回的是左值引用,所以val2依然会提供复制的方式,将values变量内容拷贝过去,但是请注意,此时makeWidget()返回的是临时对象,在该语句执行完毕后,该对象将会被析构掉,所以如果此时我们通过移动而非复制来拷贝数据,是不是效率更高呢?若要使得该语句使用移动而非复制,则data()函数返回的应该为右值对象,而非左值引用。所以,这里我们如果新增加一个data()的重载函数,使得其调用者为左值时,返回左值引用,调用者为右值时,返回的成员变量为右值对象。示例代码如下:
class Widget {
public:
std::vector<int>& data() &{
return values;
}
std::vector<int> data() &&{
return std::move(values);
}
private:
std::vector<int> values;
};
此时的客户代码为:
Widget w;
auto val = w.data(); // 调用的是左值重载版本,使用复制构造完成初始化
auto val2 = makeWidget().data(); // 调用的是右值重载版本,使用移动构造完成初始化