资源预览内容
第1页 / 共37页
第2页 / 共37页
第3页 / 共37页
第4页 / 共37页
第5页 / 共37页
第6页 / 共37页
第7页 / 共37页
第8页 / 共37页
第9页 / 共37页
第10页 / 共37页
亲,该文档总共37页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
第15章 面向对象编程 1,面向对象编程:概述 定义基类和派生类 转换与继承 构造函数和复制控制 继承情况下的类作用域 纯虚函数 容器与继承 句柄类与继承 文本查询示例,面向对象编程概述 2,1.继承:对类型之间的关系建模,共享公共的东西,仅特化本质上不同的东西。派生类能继承基类定义的成员,派生类可无须改变而使用那些与派生类型具体特性不相关的操作,并可重定义那些与派生类型相关的成员函数,将函数特化,考虑派生类型的特性。除了从基类继承成员外,派生类还可定义更多的成员。,3,class Item_base friend std:istream,4,class Bulk_item : public Item_base public: std:pair discount_policy() const return std:make_pair(min_qty, discount); / other members as before Bulk_item* clone() const return new Bulk_item(*this); Bulk_item(): min_qty(0), discount(0.0) Bulk_item(const std:string,5,double Bulk_item:net_price(size_t cnt) const if (cnt = min_qty) return cnt * (1 - discount) * price; else return cnt * price; ,动态绑定 6,动态绑定使我们能编写程序使用继承层次中任意类型的对象,无须关心对象的具体类型。使用这些类的程序无须区分函数是在基类中定义的还是在派生类中定义的。 / calculate and print price for given number of copies, applying any discounts void print_total(ostream ,7,1.虽然这个函数第二个形参是Item_base的引用,但实际上可将Item_base对象或Bulk_item对象传给它。 2.由于形参是引用且net_price是虚函数,对net_price的调用将在运行时确定。调用那个版本的net_price将依赖于传给print_total的实参。如果传给print_total的实参是一个Bulk_item对象,将运行Bulk_item中定义的应用折扣的net_price; 如果实参是一个Item_base对象,调用由Item_base定义的版本。(这就是动态绑定),定义基类8,class Item_base public: Item_base(const std:string ,基类的成员函数 9,virtual:基类应将派生类需要重定义的函数定义为虚函数。 2.protected:是private和public的混合 不能被类用户访问。(private) 可被类的派生类访问。(publc) 另外,派生 类只能通过派生类对象访问其基类的protected成员,派生类对其基类类型对象的protected成员没有特殊访问权限。,派生类 10,定义派生类时使用类派生列表指定基类。类派生列表可指定一个或多个基类。 Class classname: access-label base-class 派生类继承基类成员并可定义自己的附加成员。每个派生类对象包含两部分。从基类继承的成员和自己定义的成员。派生类只需要重定义那些与基类不同或扩展基类行为的方面。,定义派生类 11,class Bulk_item : public Item_base public: / redefines base version so as to implement bulk purchase discount policy double net_price(std:size_t) const; private: std:size_t min_qty; / minimum purchase for discount to apply double discount; / fractional discount to apply ;,派生类和虚函数 12,尽管不是必须,派生类一般会重定义所继承的虚函数。 派生类中虚函数的声明必须与基类中的定义方式完全匹配。但有一个例外,返回对基类型的引用(或指针)的虚函数在派生类中可返回基类函数所返回类型的派生类的引用(或指针),也可返回基类的引用(或指针)。 一旦函数在基类中声明为虚函数,就一直为虚函数。派生类无法改变该函数为虚函数的事实。派生类重定义虚函数时,可以用virtual,也可不用,这不是必须的。,派生类中的函数可使用基类的成员13,Double Bulk_item:net_price(size_t cnt)const if(cnt=min_qty) return cnt*(1-discount)*price; else return cnt*price; ,用作基类的类必须是已定义的 14,已定义的类才可用作基类。如果已声明Item_base,但没有定义它,则不能用作基类。这是因为,每个派生类中包含并且可以访问其基类的成员。为了使用这些成员派生类必须知道它们是什么。这一规则暗示着不可能从类自身派生出一个类。 基类本身也可以是一个派生类。 Class Base; Class D1:public Base; Class D2:public D1;,Virtual和其他成员函数 15,要触发动态绑定,必须满足两个条件:只有指定为虚函数的成员才能进行动态绑定。成员函数默认为非虚函数,非虚函数不能进行动态绑定。必须通过基类类型的引用或指针进行调用。,从派生类到基类的转换 16,Double print_total(const Item_base /p points to the item_base part of bulk,可以在运行时确定virtual 函数调用17,C动态绑定的关键是将基类类型的引用或指针绑定到派生类对象对基对象没有影响。对象本身不会改变,仍为派生类对象。对象的实际类型可能不同于该 对象引用或指针的静态类型。,18,/ calculate and print price for given number of copies, applying any discounts void print_total(ostream ,19,Item_base base; Bulk_item derived; Print_total(cout,base,10); /calls Item_base:net_price Print_totaL(cout,derived,10);/calls Bulk_item:net_price 当通过指针或引用调用基类对象的虚函数时,一会发生动态绑定。动态绑定时,引用或指针的动态类型和动态类型可能会不同。但是,对象不会变。只有可能是所调用的虚函数不同。 非虚函数总是在编译时一确定了调用那个版本。本例中,任何情况下,book调用的都是基类中的book,即使派生类中有自己 的book版本,也会调用基类中的book.,20,Item_base *basep= 即,可使用作用域操作符强制函数调用使用虚函数的特定版本。,public,privagte,protected继承21,对类所继承的成员的访问由基类中的成员访问级别和派生类派生列表中使用的访问标号共同控制。 派生类不能访问基类中的private成员。只有基类本身的成员及友元才可访问private成员。 公有继承:基类成员保持自己的访问级别 受保护的继承:基类的public和protected在派生类中都为protected 私有继承:基类的所有成员在派生类中为private,接口继承与实现继承 22,Public派生类继承基类的接口,它具有与基类相同的接口。设计良好的类层次中,public派生类的对象可以用在任何需要基类对象的地方。是最常见的继承形式。 Private和protected派生的类不继承基类的接口。这些派生类通常被称为实现继承。派生类在实现中使用继承类但继承基类的部分并未成为其接口的一部分。 继承是一种is a 的概念 ISBN和Item_base之间早一种has a 的概念。,23,Class Base public: std:size_t size() constreturn n; Protected:std:size_t n; Class Derived:private Base; Class Derived:private Base public: using Base:size; protected: using Base:n; ,默认的继承保护级别 24,Class定义的类的成员默认是私有的,struct定义的类的成员默认是公有的。 Class定义的派生类默认是private继承,struct定义的派生类默认是public继承。 Class Base; Struct D1:Base;/public inheritance Class D2:Base;/private inheritance 用struct和class定义的类没有太大的区别,除了成员默认的访问级别不同及默认的派生保护级别不同。,友元关系与继承 25,友元关系不能继承。基类的友元对派生类的成员没有特殊访问权限。如果基类被 授予友元关系,则只有基类具有特殊访问权限,该 基类的派生类不能访问授予友元关系的类。,继承与静态成员 26,如果基类定义了static成员,则整个类层次中只有一个这样的成员。无论从基类派生出多少个派生类,每个static成员只有一个实例。 Static成员遵循常规的访问控制。,转换与继承 27,可以像使用基类对象一样使用派生类对象。可以将派生类对象的引用或指针转换为基类子对象的引用或指针。 但基类只是派生类的一部分,不能像使用派生类一样使用基类。没有从基类引用或指针到派生类对象引用或指针的转换。,构造函数和复制控制 28,每个派生类对象由派生类中定义的非静态成员加上一个或多个基类子对象构成。这一事实影响着派生类对象的构造、复制、赋值和撤销。当构造、复制、赋值和撤销派生类类型对象时,也会构造、复制、赋值和撤销这些基类对象。,基类构造函数和复制控制,本身不是派生类的基类,其构造函数基本不受继承的影响。继承对基类构造函数唯一的影响是,在确定提供那些构造函数时,必须考虑一类新用户。构造函数也可以是protected或 private的。某些类需要只希望派生类使用的特殊的构造函数,这样的构造函数应定义为:protected.,派生类构造函数,每个派生类的构造函数除了初始化自己的数据成员外,还要初始化基类的数据成员。,合成的派生类默认构造函数,派生类的合成默认构造函数与非派生类只有一点不同:除了初始化派生类的数据成员外,还初始化派生类对象的基类部分。对于Bulk_item: 调用Item_Base的默认构造函数,将isbn成同初始化为空串,price成员初始化为0。 用常规变量初始化规则初始化Bulk_item的成员。也就是说,qty, discount成员会是未初始化的。,定义默认构造函数,由于Bulk_item具有内置类型的成员,所以应定义自己的默认构造函数。它用初始化列表初台化min_qty, discount。还隐式调用Item_base的默认构造函数初始化对象的基类部分。运行这个构造函数的效果是,首先使用权用Item_base的默认构造函数初始化Item_base部分,它将isbn置为空串,并 price置为0。 Item_base的构造函数执行完毕后,再
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号