zoukankan      html  css  js  c++  java
  • 读书笔记_Effective_C++_条款三十四:区分接口继承和实现继承

    这个条款书上内容说的篇幅比较多,但其实思想并不复杂。只要能理解三句话即可,第一句话是:纯虚函数只继承接口;第二句话是:虚函数既继承接口,也提供了一份默认实现;第三句话是:普通函数既继承接口,也强制继承实现。这里假定讨论的成员函数都是public的。

    这里回顾一下这三类函数,如下:

    1 class BaseClass
    2 {
    3 public:
    4     void virtual PureVirtualFunction() = 0; // 纯虚函数
    5     void virtual ImpureVirtualFunction(); // 虚函数
    6     void CommonFunciton(); // 普通函数
    7 }; 

    纯虚函数有一个“等于0”的声明,具体实现一般放在派生中(但基类也可以有具体实现),所在的类(称之为虚基类)是不能定义对象的,派生类中仍然也可以不实现这个纯虚函数,交由派生类的派生类实现,总之直到有一个派生类将之实现,才可以由这个派生类定义出它的对象。

    虚函数则必须有实现,否则会报链接错误。虚函数可以在基类和多个派生类中提供不同的版本,利用多态性质,在程序运行时动态决定执行哪一个版本的虚函数(机制是编译器生成的虚表)。virtual关键字在基类中必须显式指明,在派生类中不必指明,即使不写,也会被编译器认可为virtual函数,virtual函数存在的类可以定义实例对象。

    普通函数则是将接口与实现都继承下来了,如果在派生类中重定义普通函数,将会出现名称的遮盖(见条款33),事实上,也是极不推荐在派生类中覆盖基类的普通函数的,如果真的要这样做,请一定要考虑是否该把基类的这个函数声明为虚函数或者纯虚函数。

    下面是三类成员函数的应用:

     1 class BaseClass
     2 {
     3 public:
     4     void virtual PureVirtualFunction() = 0; // 纯虚函数
     5     void virtual ImpureVirtualFunction(); // 虚函数
     6     void CommonFunciton(); // 普通函数
     7 }; 
     8 void BaseClass::PureVirtualFunction()
     9 {
    10     cout << "Base PureVirtualFunction" << endl;
    11 }
    12 void BaseClass::ImpureVirtualFunction()
    13 {
    14     cout << "Base ImpureVirtualFunciton" << endl;
    15 }
    16 
    17 class DerivedClass1: public BaseClass
    18 {
    19     void PureVirtualFunction()
    20     {
    21         cout << "DerivedClass1 PureVirturalFunction Called" << endl;
    22     }
    23 };
    24 
    25 class DerivedClass2: public BaseClass
    26 {
    27     void PureVirtualFunction()
    28     {
    29         cout << "DerivedClass2 PureVirturalFunction Called" << endl;
    30     }
    31 };
    32 
    33 int main()
    34 {
    35     BaseClass *b1 = new DerivedClass1();
    36     BaseClass *b2 = new DerivedClass2();
    37     b1->PureVirtualFunction(); // 调用的是DerivedClass1版本的PureVirtualFunction
    38     b2->PureVirtualFunction(); // 调用的是DerivedClass2版本析PureVirtualFunction
    39     b1->BaseClass::PureVirtualFunction(); // 当然也可以调用BaseClass版本的PureVirtualFucntion
    40     return 0;
    41 }

    书上提倡用纯虚函数去替代虚函数,因为虚函数提供了一个默认的实现,如果派生类的想要的行为与这个虚函数不一致,而又恰好忘记去覆盖虚函数,就会出现问题。但纯虚函数不会,因为它从语法上限定派生类必须要去实现它,否则将无法定义派生类的对象。

    同时,因为纯虚函数也是可以有默认实现的(但是它从语法上强调派生类必须重定义之,否则不能定义对象),所以完全可以替换虚函数。

    普通函数所代表的意义是不变性凌驾与特异性,所以它绝不该在派生类中被重新定义。

    在设计类成员函数时,一般既不要将所有函数都声明为non-virtual(普通函数),这会使得没有余裕空间进行特化工作;也一般不要将所有函数都声明为virtual(虚函数或纯虚函数),因为一般会有一些成员函数是基类就可以决定下来的,而被所有派生类所共用的。这个设计法则并不绝对,要视实际情况来定。

    最后总结一下:

    1. 接口继承和实现继承不同。在public继承之下,derived class总是继承base class的接口;

    2. pure virtual函数只具体指定接口继承;

    3. impure virtual函数具体指定接口继承和缺省实现继承;

    4. non-virutal函数具体指定接口继承以及强制性实现继承。

  • 相关阅读:
    XML和HTML中常用转义字符:
    特殊符号大全
    CSS规范
    兼容ie6,ie7,ie8,firefox,chrome浏览器的代码片段
    模拟select选择器
    一行代码解决IE6/7/8/9/10兼容问题
    响应式页面之秘籍
    Global 全局样式基本设置
    webAPP meta 标签大全
    随笔小计 --
  • 原文地址:https://www.cnblogs.com/jerry19880126/p/3592964.html
Copyright © 2011-2022 走看看