《Effective Modern C++》学习笔记之条款十二:为意在改写的函数后添加override声明

override声明的作用很简单,就是当你为子类改写从父类那里继承下来的成员函数时,如果因为各种原因,导致改写失败(失败原因有很多,例如形参类型错误、函数修饰词遗漏等等),将在编译时给你明确提示。

与override相对应的时final关键字,final有两个作用,分别为:

  1. 当final修饰的是基类的虚函数时,表明改虚函数禁止在子类中被改写
  2. 当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(); // 调用的是右值重载版本,使用移动构造完成初始化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chiang木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值