mirror of
https://github.com/CnTransGroup/EffectiveModernCppChinese.git
synced 2025-03-24 08:10:19 +08:00
Item 12: updating,... i'm surprised with c++11 new feature about reference qualifier
This commit is contained in:
parent
0f2a7d19a3
commit
7cbcc69900
@ -90,7 +90,7 @@ void processPointer<const char>(const char*) = delete;
|
||||
```
|
||||
如果你想做得更彻底一些,你还要删除`const volatile void*`和`const volatile char*`重载版本,另外还需要一并删除其他标准字符类型的重载版本:`std::wchar_t`,`std::char16_t`和`std::char32_t`。
|
||||
|
||||
有趣的是,如果的类里面有一个函数模板,你可能想用`private`(经典的C++98惯例)来禁止这些函数模板实例化,但是不能这样做,因为不能给特化的模板函数指定一个不同的访问级别。如果`processPointer`是类`Widget`里面的模板函数, 你想禁止它接受`void*`参数,那么通过下面这样C++98的方法就不能通过编译:
|
||||
有趣的是,如果的类里面有一个函数模板,你可能想用`private`(经典的C++98惯例)来禁止这些函数模板实例化,但是不能这样做,因为不能给特化的模板函数指定一个不同(于函数模板)的访问级别。如果`processPointer`是类`Widget`里面的模板函数, 你想禁止它接受`void*`参数,那么通过下面这样C++98的方法就不能通过编译:
|
||||
compile:
|
||||
```cpp
|
||||
class Widget {
|
||||
@ -124,4 +124,6 @@ void Widget::processPointer<void>(void*) = delete; // 还是public,但是已
|
||||
+ 比起声明函数为private但不定义,使用delete函数更好
|
||||
+ 任何函数都能`delete`,包括非成员函数和模板实例
|
||||
|
||||
_译注:本条款`delete`,`deleted`,`删除`视情况使用,都表示一个意思.`删除函数`和`delete函数`也是如此_
|
||||
_译注:
|
||||
+本条款`delete`,`deleted`,`删除`视情况使用,都表示一个意思.`删除函数`和`delete函数`也是如此_
|
||||
+ 函数模板意指未特化前的源码,模板函数则倾向于模板实例化后的函数
|
||||
|
60
3.MovingToModernCpp/item12.md
Normal file
60
3.MovingToModernCpp/item12.md
Normal file
@ -0,0 +1,60 @@
|
||||
## Item 12:使用override声明重载函数
|
||||
条款12:使用override声明重载函数
|
||||
|
||||
在C++面向对象的世界里,涉及的概念有类,继承,虚函数。这个世界最基本的概念是派生类的虚函数重写基类同名函数。令人遗憾的是虚函数重写可能一不小心就错了。给人感觉语言的这一部分设计观点是墨菲定律不是用来遵守的,只是值得尊敬的。
|
||||
|
||||
鉴于"重写"听起来像"重载",尽管两者完全不相关,下面就通过一个派生类和基类来说明什么是虚函数重写:
|
||||
```cpp
|
||||
class Base {
|
||||
public:
|
||||
virtual void doWork(); // 基类虚函数
|
||||
…
|
||||
};
|
||||
class Derived: public Base {
|
||||
public:
|
||||
virtual void doWork(); // 重写Base::doWork(这里"virtual"是可以省略的)
|
||||
…
|
||||
};
|
||||
std::unique_ptr<Base> upb = // 创建基类指针
|
||||
std::make_unique<Derived>(); // 指向派生类对象
|
||||
// 关于std::make_unique请
|
||||
… // 参见Item1
|
||||
upb->doWork(); // 通过基类指针调用doWork
|
||||
// 实际上是派生类的doWork
|
||||
// 函数被调用
|
||||
```
|
||||
要想重写一个函数,必须满足下列要求:
|
||||
|
||||
+ 基类函数必须是`virtual`
|
||||
+ 基类和派生类函数名必须完全一样(除非是析构函数
|
||||
+ 基类和派生类函数参数必须完全一样
|
||||
+ 基类和派生类函数常量性(constness)必须完全一样
|
||||
+ 基类和派生类函数的返回值和异常说明(exception specifications)必须兼容
|
||||
除了这些C++98就存在的约束外,C++11又添加了一个:
|
||||
+ 函数的引用限定符(reference qualifiers)必须完全一样。成员函数的引用限定符是C++11很少抛头露脸的特性,所以如果你从没听过它无需惊讶。它可以限定成员函数只能用于左值或者右值。成员函数不需要`virtual`也能使用它们:
|
||||
```cpp
|
||||
class Widget {
|
||||
public:
|
||||
…
|
||||
void doWork() &; //只有*this为左值的时候才能被调用
|
||||
void doWork() &&; //只有*this为右值的时候才能被调用
|
||||
};
|
||||
…
|
||||
Widget makeWidget(); // 工厂函数(返回右值)
|
||||
Widget w; // 普通对象(左值)
|
||||
…
|
||||
w.doWork(); // 调用被左值引用限定修饰的Widget::doWork版本
|
||||
// (即Widget::doWork &)
|
||||
makeWidget().doWork(); // 调用被右值引用限定修饰的Widget::doWork版本
|
||||
// (即Widget::doWork &&)
|
||||
```
|
||||
后面我还会提到引用限定符修饰成员函数,但是现在,只需要记住如果基类的虚函数有引用限定符,派生类的重写就必须具有相同的引用限定符。如果没有,那么新声明的函数还是属于派生类,但是不会重写父类的任何函数。
|
||||
|
||||
All these requirements for overriding mean that small mistakes can make a big difference.
|
||||
Code containing overriding errors is typically valid, but its meaning isn’t what
|
||||
you intended. You therefore can’t rely on compilers notifying you if you do something
|
||||
wrong. For example, the following code is completely legal and, at first sight,
|
||||
looks reasonable, but it contains no virtual function overrides—not a single derived
|
||||
class function that is tied to a base class function. Can you identify the problem in
|
||||
each case, i.e., why each derived class function doesn’t override the base class function
|
||||
with the same name?
|
@ -22,7 +22,7 @@
|
||||
3. [Item 9:优先考虑别名声明而非typedefs](https://github.com/racaljk/EffectiveModernCppChinese/blob/master/3.MovingToModernCpp/item9.md)
|
||||
4. [Item 10:优先考虑限域枚举而非未限域枚举](https://github.com/racaljk/EffectiveModernCppChinese/blob/master/3.MovingToModernCpp/item10.md) _revised_
|
||||
5. [Item 11:优先考虑使用deleted函数而非使用未定义的私有声明](https://github.com/racaljk/EffectiveModernCppChinese/blob/master/3.MovingToModernCpp/item11.md)
|
||||
6. Item 12:使用override声明重载函数
|
||||
6. [Item 12:使用override声明重载函数](https://github.com/racaljk/EffectiveModernCppChinese/blob/master/3.MovingToModernCpp/item12.md)_updating_
|
||||
7. Item 13:优先考虑const_iterator而非iterator
|
||||
8. Item 14:如果函数不抛出异常请使用noexcept
|
||||
9. Item 15:尽可能的使用constexpr
|
||||
|
Loading…
Reference in New Issue
Block a user