第七章派生与继承2
- 格式:doc
- 大小:43.50 KB
- 文档页数:8
第七章继承和派生一、基类和派生类1. 在C++中,可以从一个类派生出另一个类,前者称为基类或父类,后者称为派生类或子类。
一个派生类可以从一个或多个基类派生。
从一个基类派生的继承称单继承,从多个基类派生的继承称多继承。
2. 单继承定义格式:class 派生类:继承方式基类{ 派生类新定义成员;};其中,“派生类”是从“基类”按指定的“继承关系”派生出的、新定义的一个类的名字。
“继承方式”有三种:(1)public 公有继承(2)private 私有继承(3) protected 保护继承3. 多继承定义格式:class 派生类:继承方式1 基类1,继承方式2 基类2,…{ 派生类新定义成员;};4. 公有继承:当派生类的继承方式是public继承时,基类的public和protected成员的访问属性在派生类中保持不变,而基类的private成员不可访问,即基类的public和protected成员分别作为派生类的public和protected成员,派生类的其他成员可以直接访问它们。
例1:class B{ private: int x; protected: int y; public: int z;…};class A:public B{ private: int a; protected: int b; public: int c;…}; A a;(1)类B是基类,有3个数据成员x、y、z,分别是private、protected、public属性。
类A是派生类,有3个数据成员a、b、c,分别是private、protected、public属性。
由于类A是从类B公有派生的,类B中的public、protected属性的成员可继承到类A中来,且保持原来的属性。
故类A中有5个数据成员,即a、b、c、y。
(2)可以通过类A的对象a直接访问public成员,即z和c,并不能访问a、b、y数据成员。
7.1 继承和派⽣考点1 继承和派⽣的基本概念 继承的实质就是建造新的派⽣类。
派⽣类从⼀个或多个以前定义的基类继承数据和函数,同时增加或重新定义数据和操作。
这就产⽣了类的层次性。
换句话说,继承就是创建⼀个具有别的类属性和⾏为的新类的能⼒。
我们把这种通过特殊化已有的类来建⽴新类的过程,叫做“类的派⽣”,原有的类叫做“基类”,新建⽴的类叫做“派⽣类”从类的成员⾓度来看,派⽣类⾃动地将基类的所有数据成员和除了构造,析构函数之外的全部成员函数作为⾃⼰的成员,这叫做“继承”。
基类和派⽣类⼜可以分别叫做“⽗类”和“⼦类”。
在C++中有两种继承:单继承和多继承。
对于单继承,派⽣类中只能有⼀个基类;对于多继承,派⽣类可以有多个基类。
单继承和多继承的基类和派⽣类的关考点2 派⽣类的定义与构成 在C++中,定义派⽣类的⼀般形式为: 单继承的定义如下: class<派⽣类名>:<继承⽅式><基类名>{<派⽣类新定义的成员>}; 多继承的定义如下: class<派⽣类名>:<继承⽅式1><基类名1>,<继承⽅式2><基类名2>, …<继承⽅式n><基类名n>{<派⽣类新定义的成员>}; 其中,<继承⽅式>即派⽣类的访问控制⽅式,⽤于规定基类成员在派⽣类中的访问权限,即基类成员在派⽣类中是公有的、私有的或保护的。
常⽤的3种继承⽅式是公有继承(public),私有继承(private)和保护继承(protected)。
缺省的类继承⽅式是私有继承private . <派⽣类新定义的成员>是指定义的派⽣类⾃⼰的成员(除了从基类继承来的所有成员之外,新增加的数据成员和函数成员)。
派⽣类的成员由两部分构成:⼀部分是从基类继承得到的,⼀部分是⾃⼰定义的新成员,所有这些成员仍然分为公有(public),私有(private)和保护(protected)3种访问性质。
第七章派生与继承2/*7.4多继承与虚基类7.4.1多继承中的二义性问题解决方式1<对象名>.<基类名>::<成员名> //数据成员<对象名>.<基类名>::<成员名>(<参数名>) //成员函数*//*#include<iostream>using namespace std;class Base1{public:int date;void fun(){cout<<"Member of Base1"<<";base1="<<date<<endl;} };class Base2{public:int date;void fun(){cout<<"Member of Base2"<<";base2="<<date<<endl;} };class Derived:public Base1,public Base2{public:int date;void fun(){cout<<"Member of Derived"<<";Derived="<<date<<endl;} };int main(){Derived obj;obj.date=1;obj.fun();obj.Base1::date=2;obj.Base1::fun();obj.Base2::date=3;obj.Base2::fun();return 0;}*//*#include <iostream>using namespace std;class Base{public:int date;void fun(){cout<<"This is Base"<<"; base="<<date<<endl;}};class Derived11:public Base{public:int date;void fun(){cout<<"This is Derived11"<<"; Derived11="<<date<<endl;}};class Derived12:public Base{public:int date;void fun(){cout<<"This is Derived12"<<"; Derived12="<<date<<endl;}};class Derived2:public Derived11,public Derived12{public:int date;void fun(){cout<<"This is Derived2"<<"; Derived2="<<date<<endl;}};int main(){Derived2 obj;obj.date=1;obj.fun();//obj.Base::date=2;//obj.Base::fun();obj.Derived11::date=3;obj.Derived11::fun();obj.Derived12::date=4;obj.Derived12::fun();return 0;}*//*7.4.2虚基类的定义虚基类格式:class<类名>:virtual<继承方式><基类名>virtual与继承方式的位置无关,但是必须位于虚基类之前,切只对紧后面的基类名起作用。
7.4.3虚基类的构造函数由于派生类的对象中只有一个虚基类对象,所以在建立一个派生类的对象时,为保证虚基类对象只被初始化一次。
这个虚基类构造函数只能被调用一次,当在构造函数的初始化列表中同时出现对虚基类和非虚基类构造函数的调用时虚基类的构造函数先于非基类的构造函数被调用;*//* #include<iostream>using namespace std;class Base{public:Base(char i){cout<<"Base'scons"<<i<<endl;}~Base(){cout<<"Base'sdes."<<endl;}private:// char c;};class Derived11:virtual public Base{public:Derived11(char i,char j):Base(i){cout<<"Derived11's cons"<<j<<endl;} ~Derived11(){cout<<"Derived11's des."<<endl;}private://char b;};class Derived12:virtual public Base{public:Derived12(char i,char j):Base(i){cout<<"Derived12's cons"<<j<<endl;} ~Derived12(){cout<<"Derived12's des."<<endl;}private://char f;};class Derived2:public Derived11,public Derived12{public:Derived2(char i,char j,char k,char l,char m,char n):Derived12(k,l),Derived11(i,j),Base(i),aa(m){cout<<"Derived2's cons"<<n<<endl;}~Derived2(){cout<<"Derived2's des."<<endl;}private:Base aa;};int main(){ Derived2 obj('a','b','c','d','e','f');return 0;}*//*7.5子类型关系1.子类型关系可以传递但不可逆,公有继承可以实现子类型关系,通过公有继承,派生类得到了基类的除了构造函数析构函数之外的所有成员。
所以派生类对象就可以作为基类的对象使用,但是他只能使用从基类继承的成员,2.具有子类型关系的基类和平派生类的对象之间满足如下赋值兼容规则。
(1)公有派生类的对象可以赋值给基类的对象,即公有派生类对象中从基类继承来的成员。
(2)公有派生类的对象可以初始化基类的引用(3)公有派生类的地址可以赋值给指向基类的指针。
*//*#include <iostream>using namespace std;class Base{public :void Who(){cout<<"class Base. "<<endl;}};class Derived1:public Base{public :void Who(){cout<<"class Derived1. "<<endl;}};class Derived2:public Base{public :void Who(){cout<<"class Derived2. "<<endl;}};int main(){Base obj1,*p;Derived1 obj2;Derived2 obj3;p=&obj1;p->Who();p=&obj2;p->Who();p=&obj3;p->Who();obj2.Who();obj3.Who();return 0;}*//*7.6虚函数与多态性一个面向对象的系统常常要求一组具有基本语义的方法能在同意接口下为不同的对象服务,这就是多态性多态性分为编译多态性和运行多态性7.6.2虚函数1,在非静态成员函数声明前加virtual就叫虚函数。
2,在派生类中重定义虚函数时,函数名,形参表和返回值类型必须保持不变。
3,虚函数在派生类中被定义后,仍是虚函数,在派生类中再次被定义后还是虚函数,不管是否加了virtual 4,对虚函数的调用分多态调用和非多态调用多态调用是指借助于指针和引用的调用,非多态调用是指不借助于指针和引用的调用,通过成员访问运算符"." 进行的。
对实函数的任何形式的调用都是非多态的。
下面是如何实现动态绑定机制的*//*#include<iostream>using namespace std;class Base{char base_name[10];public:Base(){strcpy (base_name,"BASE");}virtual char * my_name(){return base_name;}char * class_name(){return base_name;}};class Derived:public Base{char derived_name[10];public:Derived(){strcpy(derived_name,"DERIVED");}virtual char * my_name(){return derived_name;}char * class_name(){return derived_name;}};void show_ptr(Base *p){cout<<endl<<p->my_name()<<" "<<p->class_name();}void show_ref(Base &r){cout<<endl<<r.my_name()<<" "<<r.class_name();}int main(){Base bb;Derived dd;cout<<endl;show_ptr(&bb);cout<<"<==应该显示'BASE BASE'"; show_ptr(&dd);cout<<"<==应该显示'DERIVED BASE'"; cout<<endl;show_ref(bb);cout<<"<==应该显示'BASE BASE'";show_ref(dd);cout<<"<==应该显示'BASEDERIVED BASE'";cout<<endl;cout<<endl<<bb.Base::my_name()<<""<<bb.Base::class_name();cout<<"<==应该显示'BASE BASE'";cout<<endl<<dd.Base::my_name()<<""<<dd.Base::class_name();cout<<"<==应该显示'BASE BASE'";return 0;} *//*7.6.3虚析构函数只要派生类这种对析构函数进行了专门的定义,其基类的析构函数就应该声明为虚析构函数。