您的位置:首页 > 编程语言 > C语言/C++

C++primer(3版)第17章-类继承和子类型-阅读笔记

2007-08-17 09:52 309 查看
 (1)在继承机制里有两个十分重要的性质:多态性和动态绑定
   多态性:在C++中主要是指基类的指针和引用可以指向其任意派生类的能力.
(2)在面向对象的程序设计中,程序员操纵某个绑定的一个未知的实例,该绑定的类型是一个无限的集合,这些类型通过继承层次结构被绑定起来,在理论上对于层析的广度和深度没有限制,同时
在C++中这只能通过操纵基类指针和引用来实现
(3)void *型的指针可以被描述为多态,但是语言本身没有支持它,必须由程序员自己来管理,程序员可以通过"显式强制类型转换,以及记录实际类型的判别式"实现这一性质.
(4)C++支持多态的几种方式:
 -----通过隐式转换,从"派生类指针或引用"转换到"其共有基类类型的指针或引用"
    Query *pquery = new NameQuery("Glass");// Query是NameQuery的基类
 -----通过虚函数机制
    pquery->eval(); //eval()是基类中的虚函数,在派生类里得到实现
 -----通过dynamic_cast和typeid操作符
 if( NameQuery *pnq = dynamic_cast<NameQuery*>(pquery))
           ......
(5)在派生表中指定的类必须首先被定义好,方可指定为基类;派生类的前向声明不能包括它的派生表,而只需要类名.
(6)基类中声明为public,protected以及private时的访问规则:
 public:可以在任何范围内访问
 private:只能在类本身范围内访问
 protected:可以在类本身及其派生类范围内访问
(7)基类中包含的内容:
   ----被所有派生类支持的操作集,其中包括派生类类型改写的操作(虚函数)以及派生类之间共享的非虚函数
   ----派生类公共的数据成员集
(8)非静态数据成员:每个对象都需要自己拥有自己的版本的数据成员
   静态数据成员:所有类对象只需要共享的同一个数据成员
(9)虚函数和纯虚函数
   ----二者都是需要在派生类中重新实现的函数
   ----前者在基类中有定义(通常是空定义),此时的基类可以有自己的对象,如果通过自己的对象访问该函数,则执行的是基类中的函数,如果通过指向派生类的指针或引用访问该函
       数,则访问的是派生类重新实现的函数实体
   ----后者在基类中一般没有定义,基类被称为抽象类,不能定义自己的对象,只能定义指针或是引用,并通过指针或是引用访问派生类中的实现.如果对其定义了,则不能通过虚拟机
       制访问它,只能通过类域限定符静态访问它(P760)
(10)派生类对象是由其基类的非静态数据成员组成的子对象,以及由派生类的非静态数据成员构成的.
(11)当基类和派生类里有同名的函数,且基类中的不是虚函数时,通过派生类访问的只能是派生类的函数,而不能和基类的函数形成重载.除非使用using 将基类的该名函数引入到派
    生类中.
(12)派生类可以直接访问该类其他对象的protected基类成员,以及该类其他对象的protected和private成员.
(13)基类指针pb,除了在基类中被声明、并且在派生类中被改写的虚函数,没有办法通过pb直接访问派生类中的成员。
    基类指针只能访问在该类中被声明(或继承)的数据成员和成员函数,包括虚函数,而与它可能指向的实际对象无关.
    优点:虚成员函数的执行不会因为实际类型不存在函数实例而失败.如果不存在某个适当的实例,则程序不能被编译
         虚函数调用通常不会比"通过指针间接调用函数"的开销更大
(14)如果一个派生类希望直接访问其基类的私有成员,则该基类必须显式地把派生类声明为友元,另外,友元关系是不能继承的,例如:由Query派生NameQuery,再由NameQuery派生StringQuery,
    其中NameQuery是Query的友元,则NameQuery对Query有特权,但是StringQuery对Query没有特权.
(15)派生类中构造函数的调用顺序:
   ----基类构造函数.如果有多个基类,则构造函数的调用顺是某基类在类派生表中出现的顺序,而不是它们在成员初始化表中的顺序
   ----成员类对象构造函数.如果有多个成员类对象,则构造函数的调用顺序是对象在类中被声明的顺序,而不是它们出现在成员初始化表中的顺序
   ----派生类构造函数,作为一般规则,派生类的构造函数应该不能直接向一个基类数据成员赋值,而是把值传递给适当的基类构造函数.
(16)派生类只能合法地调用其直接基类的构造函数.(P748)
(17)如果基类是一个抽象类,而且在派生类中未对基类的纯虚函数进行实现,则派生类也是抽象类.
(18)派生类的析构函数函数的调用顺与它的构造函数的调用顺序相反.
(19)为了是虚函数的派生类实例能够改写其基类的活动实例,它的原型必须与基类完全匹配,返回类型也必须相同,但有一个特例,派生类实例的返回值可以是基类的实例返回类型的
    公有派生类类型.
(20)通过基类指针或引用调用派生类实例,则传递给它的缺省实参是由基类指定的.因为虚函数具体指向的实际类型是在运行时刻决定的,但是传递给虚函数的实参不是在运行时刻
    决定的,而是在编译时刻根据被调用函数的对象的类型决定的.
(21)如果在基类的构造函数中调用了一个虚函数,而基类和派生类都定义了该函数的实例,则调用的结果在逻辑上是未定义的.程序可能会崩溃.
(22)对于派生类对象,在基类的析构函数中也是如此:派生类部分也是未定义的,但是,这次不是因为还没有构造,而是因为它已经被销毁.
(23)按成员赋值与按成员初始化类似.如果存在一个显式的拷贝赋值操作符,则调用它,用一个类对象向另一个类对象赋值,否则,应该缺省的按成员赋值.
    如果存在基类,则首先对基类子对象按成员赋值.如果基类提供了一个显式的拷贝赋值操作符,则调用它.否则,递归地对基类和基类子对象的成员应用缺省按成员赋值的动作.
(24)不像拷贝构造函数那样,拷贝赋值操作没有特殊的部分可以通过它来调用基类的赋值操作符.要想调用基类的赋值操作符,可以有两种语法形式:通过显式的调用,也可以通过显式的强制类型转换.

   inline NotQuery& NotQuery::operator=(const NotQuery &rhs)
   {
 //阻止自我赋值
 if( &rhs != this)
 {
  //调用Query拷贝赋值操作符
  this->Query::operator=( rhs );  //显式调用
     
  //拷贝操作数
  _op = rhs->_op->clone();
 }
 return *this.
   }

   //强制转换
   (*static_cast<Query*>(this)) = rhs;
(25)作为一般规则,建议将层次结构的根基类的析构函数声明为虚拟的.基类的析构函数不应该是protected.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息