《面向对象技术(C++ Primer)第15章.ppt》由会员分享,可在线阅读,更多相关《面向对象技术(C++ Primer)第15章.ppt(37页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第15章 面向对象编程 1面向对象编程:概述定义基类和派生类转换与继承构造函数和复制控制继承情况下的类作用域纯虚函数容器与继承句柄类与继承文本查询示例面向对象编程概述 21.继承:对类型之间的关系建模,共享公共的东西,仅特化本质上不同的东西。派生类能继承基类定义的成员,派生类可无须改变而使用那些与派生类型具体特性不相关的操作,并可重定义那些与派生类型相关的成员函数,将函数特化,考虑派生类型的特性。除了从基类继承成员外,派生类还可定义更多的成员。3class Item_base friend std:istream&operator(std:istream&,Item_base&);friend
2、 std:ostream&operator(std:ostream&,const Item_base&);public:virtual Item_base*clone()const return new Item_base(*this);public:Item_base(const std:string&book=,double sales_price=0.0):isbn(book),price(sales_price)std:string book()const return isbn;virtual double net_price(std:size_t n)const return n*
3、price;/no work,but virtual destructor needed if base pointer that points to a derived object is ever deleted virtual Item_base()private:std:string isbn;/identifier for the itemprotected:double price;/normal,undiscounted price;4class Bulk_item:public Item_base public:std:pair discount_policy()const r
4、eturn 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&book,double sales_price,std:size_t qty=0,double disc_rate=0.0):Item_base(book,sales_price),min_qty(qty),discount(disc_rate)
5、/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;5double Bulk_item:net_price(size_t cnt)const if(cnt=min_qty)return cnt*(1-discou
6、nt)*price;else return cnt*price;动态绑定 6动态绑定使我们能编写程序使用继承层次中任意类型的对象,无须关心对象的具体类型。使用这些类的程序无须区分函数是在基类中定义的还是在派生类中定义的。/calculate and print price for given number of copies,applying any discounts void print_total(ostream&os,const Item_base&item,size_t n)os ISBN:item.book()/calls Item_base:book tnumber sold:n
7、 ttotal price:/virtual call:which version of net_price to call is resolved at run time _price(n)=min_qty)return cnt*(1-discount)*price;else return cnt*price;用作基类的类必须是已定义的 14已定义的类才可用作基类。如果已声明Item_base,但没有定义它,则不能用作基类。这是因为,每个派生类中包含并且可以访问其基类的成员。为了使用这些成员派生类必须知道它们是什么。这一规则暗示着不可能从类自身派生出一个类。基类本身也可以是一个派生类。Cla
8、ss Base;Class D1:public Base;Class D2:public D1;Virtual和其他成员函数 15要触发动态绑定,必须满足两个条件:只有指定为虚函数的成员才能进行动态绑定。成员函数默认为非虚函数,非虚函数不能进行动态绑定。必须通过基类类型的引用或指针进行调用。从派生类到基类的转换 16Double print_total(const Item_base&,size_t);Item_base item;/object of base typePrint_total(item,10);/passes reference to an Item_base objectI
9、tem_base*p=&item;/p points to an Item_base objectBulk_item bulk;/object of derived typePrint_total(bulk,10);/passes reference to the item_base part of bulkP=&bulk;/p points to the item_base part of bulk可以在运行时确定virtual 函数调用17C动态绑定的关键是将基类类型的引用或指针绑定到派生类对象对基对象没有影响。对象本身不会改变,仍为派生类对象。对象的实际类型可能不同于该 对象引用或指针的
10、静态类型。18/calculate and print price for given number of copies,applying any discounts void print_total(ostream&os,const Item_base&item,size_t n)os ISBN:item.book()/calls Item_base:book tnumber sold:n ttotal price:/virtual call:which version of net_price to call is resolved at run time _price(n)Item_ba
11、se:net_price(42);即,可使用作用域操作符强制函数调用使用虚函数的特定版本。public,privagte,protected继承21对类所继承的成员的访问由基类中的成员访问级别和派生类派生列表中使用的访问标号共同控制。派生类不能访问基类中的private成员。只有基类本身的成员及友元才可访问private成员。公有继承:基类成员保持自己的访问级别受保护的继承:基类的public和protected在派生类中都为protected私有继承:基类的所有成员在派生类中为private接口继承与实现继承 22Public派生类继承基类的接口,它具有与基类相同的接口。设计良好的类层次中,
12、public派生类的对象可以用在任何需要基类对象的地方。是最常见的继承形式。Private和protected派生的类不继承基类的接口。这些派生类通常被称为实现继承。派生类在实现中使用继承类但继承基类的部分并未成为其接口的一部分。继承是一种is a 的概念ISBN和Item_base之间早一种has a 的概念。23Class Basepublic:std:size_t size()constreturn n;Protected:std:size_t n;Class Derived:private Base;Class Derived:private Base public:using Bas
13、e:size;protected:using Base:n;默认的继承保护级别 24Class定义的类的成员默认是私有的,struct定义的类的成员默认是公有的。Class定义的派生类默认是private继承,struct定义的派生类默认是public继承。Class Base;Struct D1:Base;/public inheritanceClass D2:Base;/private inheritance用struct和class定义的类没有太大的区别,除了成员默认的访问级别不同及默认的派生保护级别不同。友元关系与继承 25友元关系不能继承。基类的友元对派生类的成员没有特殊访问权限。如
14、果基类被 授予友元关系,则只有基类具有特殊访问权限,该 基类的派生类不能访问授予友元关系的类。继承与静态成员 26如果基类定义了static成员,则整个类层次中只有一个这样的成员。无论从基类派生出多少个派生类,每个static成员只有一个实例。Static成员遵循常规的访问控制。转换与继承 27可以像使用基类对象一样使用派生类对象。可以将派生类对象的引用或指针转换为基类子对象的引用或指针。但基类只是派生类的一部分,不能像使用派生类一样使用基类。没有从基类引用或指针到派生类对象引用或指针的转换。构造函数和复制控制 28每个派生类对象由派生类中定义的非静态成员加上一个或多个基类子对象构成。这一事实
15、影响着派生类对象的构造、复制、赋值和撤销。当构造、复制、赋值和撤销派生类类型对象时,也会构造、复制、赋值和撤销这些基类对象。基类构造函数和复制控制本身不是派生类的基类,其构造函数基本不受继承的影响。继承对基类构造函数唯一的影响是,在确定提供那些构造函数时,必须考虑一类新用户。构造函数也可以是protected或 private的。某些类需要只希望派生类使用的特殊的构造函数,这样的构造函数应定义为:protected.派生类构造函数每个派生类的构造函数除了初始化自己的数据成员外,还要初始化基类的数据成员。合成的派生类默认构造函数派生类的合成默认构造函数与非派生类只有一点不同:除了初始化派生类的数
16、据成员外,还初始化派生类对象的基类部分。对于Bulk_item:调用Item_Base的默认构造函数,将isbn成同初始化为空串,price成员初始化为0。用常规变量初始化规则初始化Bulk_item的成员。也就是说,qty,discount成员会是未初始化的。定义默认构造函数由于Bulk_item具有内置类型的成员,所以应定义自己的默认构造函数。它用初始化列表初台化min_qty,discount。还隐式调用Item_base的默认构造函数初始化对象的基类部分。运行这个构造函数的效果是,首先使用权用Item_base的默认构造函数初始化Item_base部分,它将isbn置为空串,并 pri
17、ce置为0。Item_base的构造函数执行完毕后,再初始化 Bulk_item部分的成员,并执行构造函数的函数体。向基类构造函数传递实参Class Bulk_item:public Item_base public:Bulk_item(const std:string&book,double sales_price,std:size_t qty=0,double disc_rate=0.0):Item_base(book,sales_price),min_qty(qty),discount(disc_rate)调用方法:Bulk_item bul(“0-201-82470-1”,50,5,0
18、.19);在派生类构造函数中使用默认实参Class Bulk_item:public Item_basePublic:Bulk_item(const std:string&book=“”,double sales_price=0.0,std:size_t qty=0,double disc_rate=0.0):Item_base(book,sales_price),min_qty(qty),discount(disc_rate)以上构造函数中为每个形参提供默认值,可用0到4个实参使用它。只能初始化直接基类一个类只能初始化自己的直接基类。直接基类就是在派生列表中指定的类。设C类从B类派生,B类从
19、A类派生。则C类中包含着B类和A类中定义的成员。但B是C的直接基类。A为C的间接基类。虽然每个C类对象包含一个A类部分,但C的构造函数不能直接初始化A。需要C初始化B,B的构造函数再初始化A。这一限制的原因是,类B的作者已经指定了怎样构造和初始化B类型的对象。像B的任何用户一样,类C的作者无权改变这个规约。析构函数析构函数的工作用于撤销成员。但是,派生类的析构函数不负责撤销基类对象的成员。每个析构函数只负责清除自己的成员。编译器总是显式调用派生类对象基类部分的析构函数。Class Derived:public Base public:/Base:Base invoked automatical
20、ly Derived()/*do what it takes to clean up derived members*/虚析构函数当删除指向动态分配对象的指针时,需要运行析构函数在释放对象之前清除对象。处理继承层次中的对象时,指针的静态类型可能与被删除对象的动态类型不同,可能会删除实际指向派生类对象的基类类型指针。如果删除基类指针,则需要运行基类的析构函数并清除基类的成员。如果对象实际上是派生类型时,则没有定义该 行为。要保证运行适当的析构函数,基类中的析构函数必须为虚函数。如果析构函数为虚函数,通过指针调用时,运行那个析构函数将因指针所指对象类型的不同而不同。析构函数是虚函数的性质都将被继承。通常,即使析构函数没有工作要做,继承层次的要类也应该定义一个虚析构函数。