继承:ios
覆盖:函数
若派生类中定义了一个与基类中同名的成员,则会出现基类与派生类有同名成员的状况,这是容许的。同名的成员既能够是成员变量,也能够是成员函数。这种状况下,若在派生类的成员函数中访问这个同名成员,或经过派生类对象访问这个同名成员时,除非特别指明,访问的就是派生类中的成员,这种状况叫“覆盖”,即派生类的成员覆盖基类的同名成员。覆盖也称为重定义或是重写。对于成员函数来讲,派生类既继承了基类的同名成员函数,又在派生类中重写了这个成员函数。这称为函数重定义,也称为同名隐藏。“隐藏”的意思是指,使用派生类对象调用这个名字的成员函数时,调用的是派生类中定义的成员函数,即隐藏了基类中的成员函数。spa
派生类能够改变基类中成员的访问权限
空类也能够做为基类,也就是说,空类能够派生子类:设计
class emptyClass{ }; //空基类 class subemptyClass : public emptyClass{ }; //派生类
类的大小指针
一、友元code
若是基类有友元类或友元函数,则其派生类不会因继承关系而也有此友元类或友元函数。若是基类是某类的友元,则这种友元关系是被继承的。即被派生类继承过来的成员函数,若是原来是某类的友元函数,那么它做为派生类的成员函数仍然是某类的友元函数。总之,基类的友元不必定是派生类的友元;基类的成员函数是某类的友元函数,则其做为派生类继承的成员函数还是某类的友元函数。对象
#include<iostream> using namespace std; class another; //前向引用声明 //基类 class Base { private: float x; public: void print(const another &K); }; //派生类 class Derived:public Base { private: float y; }; //其余类 class another{private: int aaa; public: another(){ aaa=100; } friend void Base::print(const another &K);//基类的成员函数声明为本类的友元 }; void Base::print(const another &K){ cout<<"Base:"<<K.aaa<<endl; //能够访问私有成员变量 } int main(){ Base a; Derived d; another ano; //aaa 初始化为100 a.print(ano); //输出为:Base:100 d.print(ano); //输出为:Base:100 return 0; }
二、静态属性blog
若是基类中的成员是静态的,则在其派生类中,被继承的成员也是静态的,即其静态属性随静态成员被继承。
若是基类的静态成员是公有的或是保护的,则它们被其派生类继承为派生类的静态成员。访问这些成员时,一般用“<类名>::<成员名>”的方式引用或调用。不管有多少个对象被建立,这些成员都只有一个拷贝,它为基类和派生类的全部对象所共享。继承
#include<iostream> using namespace std; // 基类 class Base { private: float x; public: static int staV; Base(){ staV++; } }; int Base::staV=0; //派生类 class Derived: public Base { private: float y; public: Derived( ){ staV++; } }; int main(){ Base a; cout<< "Base:" <<a.staV<<endl; //输出1 Derived d; cout<< "Derived:" << d.staV<<endl; //输出3(建立子类对象会调用父类构造器,而后调用自身的构造器) return 0; }
三、继承之间的访问关系内存
#include<iostream> using namespace std; class CB{ public: int a; CB(int x){ a=x; } void showa(){ cout<<"Class CB--a="<<a<<endl; } }; class CD:public CB{ public: int a; //与基类a同名 //x用来初始化基类的成员变量a CD(int x,int y):CB(x) { a=y; } //与基类showa同名 void showa() { cout<<"Class CD--a="<<a<<endl; } //访问派生类a void print2a(){ cout<<"a=" << a<<endl; //访问基类a cout<<"CB::a="<<CB::a<<endl; } }; int main(){ CB CBobj(12); CBobj.showa();//Class CB--a=12 CD CDobj(48,999); CDobj.showa(); //访问派生类的showa () Class CD--a=999 CDobj.CB::showa(); //访问基类的showa () Class CB--a=48 cout<<"CDobj.a="<<CDobj.a<<endl; // CDobj.a=999 cout<<"CDobj.CB::a="<<CDobj.CB::a<<endl;//CDobj.CB::a=48 }
四、protected访问范围说明符
#include<iostream> using namespace std; class CB1{ public: int a; CB1 (int x){ a=x; } void showa(){ cout<<"ClassCB1==>a="<<a<<endl; } }; class CB2{ public: int a; CB2 (int x){ a=x; } void showa(){ cout<<"ClassCB1==>a="<<a<<endl; } }; //多重继承,两个基类 class CD:public CB1,public CB2 { public: int a; //与两个基类成员变量a重名 CD(int x,int y,int z):CB1(x) ,CB2(y){ a=z; } //与两个基类成员函数showa()重名 void showa() { cout<<"Class CD==>a="<<a<<endl; } void print3a(){ cout<<"a="<<a<<endl; cout<<"CB1::a="<<CB1::a<<endl; cout<<"CB2::a="<<CB2::a<<endl; } }; int main(){ CB1 CB1obj(11); CB1obj.showa();//ClassCB1==>a=11 CD CDobj(101,202,909); CDobj.showa(); //调用派生类的showa() //Class CD==>a=909 CDobj.CB1::showa(); //调用基类的showa() //ClassCB1==>a=101 cout<<"CDobj.a="<<CDobj.a<<endl;//访问派生类成员a //CDobj.a=909 cout<<"CDobj.CB2::a="<<CDobj.CB2::a<<endl; //CDobj.CB2::a=202 }
二、多重继承的二义性
⚫ 若是派生类中新增了同名成员,则派生类成员将隐藏全部基类的同名成员。使用“派生类对象名.成员名”或“派生类对象指针->成员名”的方式能够惟一标识和访问派生类新增成员。这种状况下,不会产生二义性。
⚫ 若是派生类中没有新增同名成员,当知足访问权限时,使用“派生类对象名.成员名”或“派生类对象指针->成员名”方式时,系统没法判断究竟是调用哪一个基类的成员,从而产生二义性。为了不二义性,必须经过基类名和做用域分辨符来标识成员。
⚫ 当要访问派生类对象中的某个变量时,添加“基类::”做为前缀,指明须要访问从哪一个基类继承来的,从而能够排除二义性。
三、继承权限控制
设计继承类时,须要使用继承方式说明符指明派生类的继承方式。继承方式说明符能够是public(公有继承)、private(私有继承)或protected(保护继承)
⚫类型兼容规则是指在须要基类对象的任何地方,均可以使用公有派生类的对象来替代,也称为赋值兼容规则。在公有派生的状况下,有如下3条类型兼容规则。
⚫上述3条规则反过来是不成立的。例如,不能把基类对象赋值给派生类对象。在进行替代以后,派生类对象就能够做为基类的对象使用了,但只能使用从基类继承的成员。
⚫若是类B为基类,类D为类B的公有派生类,则类D中包含了基类B中除构造函数、析构函数以外的全部成员。这时,根据类型兼容规则,在基类B的对象能够出现的任何地方,均可以用派生类D的对象来替代。假设有如下的声明:
class B{…} class D : public B{…} B b1, *pb1; D d1;
⚫这时,派生类对象能够隐含转换为基类对象,即用派生类对象中从基类继承来的成员变量的值,逐个为基类对象的成员变量的值进行赋值。b1=d1;
⚫派生类的对象也能够用来初始化基类对象的引用,即:B &rb=d1;
⚫派生类对象的地址能够隐含转换为指向基类的指针,即派生类对象的地址赋给基类指针:pb1=&d1;
⚫因为类型兼容规则的引入,对于基类及其公有派生类的对象,可使用相同的函数统一进行处理。由于当函数的形参为基类的对象(或引用、指针)时,实参能够是派生类的对象(或指针),从而没有必要为每个类设计单独的模块,大大提升了程序的效率。
保护继承中,基类的公有成员和保护成员都以保护成员的身份出如今派生类中,而基类的私有成员不能够直接访问。这样,派生类的其余成员能够直接访问从基类继承来的公有和保护成员,但在类外经过派生类的对象没法直接访问它们。
class A{}; class B:private A{};//私有继承 class C:protected A{};//保护继承