条款12.为意在改写的函数添加override声明

为意在改写的函数添加override声明

class Base{
public:
    virtual void doWork();		//基类中的虚函数
};

class Derived : public Base{
public:
    virtual void doWork();		//改写了Base::dowork
};

std::unique_ptr<Base> upb = std::make_unique<Derived>();	//创建基类指针,指向派生类对象

upb->doWork();			//通过基类指针调用doWork
						//结果是派生类函数被调用

如果要改写动作真的发生,以下要求必须满足

  • 基类中的函数必须是虚函数
  • 基类和派生类中的函数名字必须完全相同(析构函数例外)
  • 基类和派生类中的函数形参类型必须完全相同
  • 基类和派生类中的函数返回值和异常规格必须兼容
  • 基类和派生类中的函数引用饰词必须完全相同
    • 函数引用饰词是为了限制成员函数仅用于左值或右值,带有引用饰词的成员函数,不必是虚函数
class Widget{
public:
    void doWork() &;		//这个版本的doWork仅在*this是左值时调用
    
    void doWork() &&;		//这个版本的doWork仅在*this是右值时调用
};

Widget makeWidget();		//工厂函数

Widget w;				//普通对象(左值)

w.doWork();				//以左值调用Widget::doWork
						//即Widget::doWork &

makeWidget().doWork();	//以右值调用Widget::doWork
						//即Widget::doWork &&

如果基类中的虚函数带有引用饰词,则派生类要对该函数进行改写,必须也带有完全相同的引用饰词。如果不然,那么这些声明了的函数在派生类中依然存在,只是它们不会改写基类中的任何函数

C++11提供了一种方法来显式地标明派生类中的函数是为了改写基类版本,为其加上override声明

class Base{
public:
    virtual void mf1() const;
    virtual void mf2(int x);
    virtual void mf3() &;
    virtual void mf4() const;
};

class Derived : public Base{
public:
    virtual void mf1() const override;
    virtual void mf2(int x) override;
    virtual void mf3() & override;
    virtual void mf4() const override;
};

C++11中的两个语境关键字finaloverride,它们的特色是,语言保留这两个关键字,但仅在特定语境下保留。对于override的情况下,它仅出现在成员函数声明的末尾时才有保留意义。这就意味着,如果你有一些遗留代码,其中已经用过override这个名字的话,你不必为了升级到C++11而改名。

如果我们想撰写一个函数,仅接受传入左值实参,则会声明一个非const左值引用形参:

void doSomething(Widget& w);		//仅接受左值的Widget类型

如果我们想撰写一个函数,仅接受传入右值实参,

void doSomething(Widget&& w);		//仅接受右值的Widget类型

成员函数引用饰词的作用就是针对发起成员函数调用的对象,即*this,加一些区分度。这和成员函数声明末尾加一个const的情形一摸一样:后者表明发起成员函数调用的对象,即*this,应该是const

class Widget{
public:
    using DataType = std::vector<double>;
    
    DataType& data() &			//对于左值类型,返回左值
    { return values; }
    
    DataType data() &&
    { return std::move(values); } 	//对于右值Widget类型,返回右值

private:
    DataType values;
};

左值引用类型的重载版本,返回的是左值引用(即一个左值);而右值引用类型的重载版本,则返回的是一个临时对象(即一个右值)。

//创建Widget类型对象的工厂函数
Widget makeWidget();

Widget w;

auto vals1 = w.data();		//调用Widget::data的左值重载版本
							//vals1采用复制构造完成初始化

auto vals2 = makeWidget().data();	//调用Widget::data的右值重载版本
									//vals2采用移动构造函数完成初始化

要点速记

  • 为意在改写的而函数添加override声明
  • 成员函数引用饰词使得对于左值和右值对象的处理能够区分开
上一篇:Flutter Widget -Text


下一篇:oracle集合union、union all、intersect、minus