【Effection C++】读书笔记 条款07~条款08

【Effection C++】读书笔记 Part2 构造/析构/赋值运算

条款07:为多态基类声明virtual析构函数

  1. 带有多态(polymorphic)性质的base classes应该声明一个virtual析构函数。如果class带有virtual函数,应该拥有一个virtual函数。主要是能够通过基类的接口而正确处理派生类的对象。
  2. 类的设计目的如果不是作为base classes使用,或者不是为了具备多态性而使用,那么就不应该声明为virtual析构函数。

C++11中的final和override关键字

对于旧标准,如果一个类设计之处就不是为了做基类,如STL中的vector,string,那么当我们继承其的时候,编译器是没有办法报错的。也就会导致未定义的行为。

但是在新标准里面,关键字final的使用可以让我们避免许多错误。

  1. 将类标记为final,意味着此类将不可能再做其他类的基类,任何试图继承此类的行为,编译器都将报错。
  2. 将类中的成员虚函数标记为final,则意味着任何派生类都将不能对此函数进行重写。否则,编译器将报错。
//案例一:final修饰的类不能被继承
struct B1 final { };
struct D1 : B1 { }; // 错误!不能从 final 类继承!
//案例二:final修饰的虚函数不能继承
struct B2
{
    virtual void f() final {} // final 函数
};

struct D2 : B2
{
    virtual void f() {}
};

除此之外,还有override关键字还可以帮助我们避免许多问题:

对于一个派生类,如果我们想要重写基类的虚函数的时候可以使用override关键字来修饰,它向编译器表明目前我正在重写继承自父类的虚函数。如果当前真的正在重写继承自父类的虚函数,那么编译器并不会做任何反应,但是如果你并不是在重写继承自父类的虚函数(考虑一下有些时候,很有可能导致参数错误而没有重写对应的父类虚函数),编译器就会提出错误。

struct B3
{
    virtual void g(int) {}
};

struct D3 : B3
{
    virtual void g(int) override {} // OK
    virtual void g(double) override {} // Error
};

这两个关键字可以帮助我们解决许多潜在的问题,除此之外,它还暗示编译器可以做一些优化。如对于标记为final的类,编译器可以不为其生成虚函数表,这样子的效率显然更高。对于标记为final的函数,编译器能够了解到当前函数必然不会被覆盖,因而也就可以将其从虚函数表中删除。

条款08:别让异常逃离出析构函数

对于语法上而言,C++并不禁止析构函数吐出异常,但是C++绝对不建议你在析构函数中抛出异常。

  1. 析构函数绝对不要吐出异常,如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们或者结束程序。
  2. 如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。

你可能感兴趣的:(读书笔记,effective-c++,c++)