重写:在派生类中的虚函数实现,会改写基类中对应虚函数的实现
重写的要求:
基类中的函数必须是虚函数
基类和派生类中的函数名字必须完全相同(析构函数例外)
基类和派生类中的函数形参型别必须完全相同
基类和派生类的函数常量性(constness)必须完全相同
基类和派生类中的函数返回值和异常规格必须兼容
基类和派生类中的函数引用修饰词必须完全相同。
上面提到的重写要求前5点是C++98的要求,第6点是C++11对于重写的要求。
成员函数引用修饰词包含左值引用、右值引用修饰词,带有左值引用修饰词的成员函数只有*this
是左值时调用,带有右值引用修饰词的成员函数只有*this
是右值时调用,
例如:
class Person
{
public:
void DoWork() &;
void DoWork() &&;
}
// 返回Person右值
Person CreatePerson();
Person objPerson;
// 以Person对象左值调用成员函数DoWork() &
objPerson.DoWork()
// 以Person对象右值调用成员函数DoWork() &&
CreatePerson().DoWork()
在子类中增加重写override关键字有助于编译器检测所有与重写相关的问题,而没有这个关键字时很容易造成隐藏,关于隐藏可以参考这篇文章, override只有出现在成员函数声明的结尾才有意义,这就意味着,如果有一些C++11之前的代码用过了override这个名字也不必为了升级到C++11而改名:
class Person
{
public:
void override();
}
示例:
class Combat
{
public:
Combat()
{
}
Combat(const Combat& obj)
{
cout << "Combat(const Combat& obj)" << endl;
}
Combat(Combat&& obj)
{
cout << "Combat(Combat&& obj)" << endl;
}
};
class Person
{
public:
void DoWork() &;
Combat& GetCombat()
{
return m_objCombat;
}
public:
Combat m_objCombat
}
Person CreatePerson()
{
return Person();
}
有如下调用:
CreatePerson().DoWork()
我们在成员函数后面增加了左值引用修饰词,也就意味着只有左值才能调用,编译期发生错误
auto combat = CreatePerson().GetCombat()
GetCombat成员函数后面没有任何引用修饰词,当按照这种方式调用时,
其实发生了从临时对象(右值)返回Combat对象的左值引用,并以此为参数调用Combat对象的拷贝构造函数,
而对于临时对象的拷贝更应该是移动拷贝操作而非左值拷贝,从而避免牺牲效率,对于上例的修改:
class Person
{
public:
void DoWork() &;
Combat& GetCombat() &
{
return m_objCombat;
}
Combat GetCombat() &&
{
return std::move(m_objCombat);
}
public:
Combat m_objCombat
}
为意在重写的函数添加override声明
成员函数引用饰词使得对于左值和右值对象*this
的处理能够区分开来