标签:位置 初始 other 静态成员函数 类对象 image 子类 大小 情况
继承:
覆盖:
若派生类中定义了一个与基类中同名的成员,则会出现基类与派生类有同名成员的情况,这是允许的。同名的成员既可以是成员变量,也可以是成员函数。这种情况下,若在派生类的成员函数中访问这个同名成员,或通过派生类对象访问这个同名成员时,除非特别指明,访问的就是派生类中的成员,这种情况叫“覆盖”,即派生类的成员覆盖基类的同名成员。覆盖也称为重定义或是重写。对于成员函数来说,派生类既继承了基类的同名成员函数,又在派生类中重写了这个成员函数。这称为函数重定义,也称为同名隐藏。“隐藏”的意思是指,使用派生类对象调用这个名字的成员函数时,调用的是派生类中定义的成员函数,即隐藏了基类中的成员函数。
派生类可以改变基类中成员的访问权限
空类也可以作为基类,也就是说,空类可以派生子类:
class emptyClass{ }; //空基类 class subemptyClass : public emptyClass{ }; //派生类
类的大小
1、友元
如果基类有友元类或友元函数,则其派生类不会因继承关系而也有此友元类或友元函数。如果基类是某类的友元,则这种友元关系是被继承的。即被派生类继承过来的成员函数,如果原来是某类的友元函数,那么它作为派生类的成员函数仍然是某类的友元函数。总之,基类的友元不一定是派生类的友元;基类的成员函数是某类的友元函数,则其作为派生类继承的成员函数仍是某类的友元函数。
#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; }
2、静态属性
如果基类中的成员是静态的,则在其派生类中,被继承的成员也是静态的,即其静态属性随静态成员被继承。
如果基类的静态成员是公有的或是保护的,则它们被其派生类继承为派生类的静态成员。访问这些成员时,通常用“<类名>::<成员名>”的方式引用或调用。无论有多少个对象被创建,这些成员都只有一个拷贝,它为基类和派生类的所有对象所共享。
#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; }
3、继承之间的访问关系
#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 }
4、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 }
2、多重继承的二义性
? 如果派生类中新增了同名成员,则派生类成员将隐藏所有基类的同名成员。使用“派生类对象名.成员名”或“派生类对象指针->成员名”的方式可以唯一标识和访问派生类新增成员。这种情况下,不会产生二义性。
? 如果派生类中没有新增同名成员,当满足访问权限时,使用“派生类对象名.成员名”或“派生类对象指针->成员名”方式时,系统无法判断到底是调用哪个基类的成员,从而产生二义性。为了避免二义性,必须通过基类名和作用域分辨符来标识成员。
? 当要访问派生类对象中的某个变量时,添加“基类::”作为前缀,指明需要访问从哪个基类继承来的,从而可以排除二义性。
3、继承权限控制
设计继承类时,需要使用继承方式说明符指明派生类的继承方式。继承方式说明符可以是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;
?由于类型兼容规则的引入,对于基类及其公有派生类的对象,可以使用相同的函数统一进行处理。因为当函数的形参为基类的对象(或引用、指针)时,实参可以是派生类的对象(或指针),从而没有必要为每一个类设计单独的模块,大大提高了程序的效率。
标签:位置 初始 other 静态成员函数 类对象 image 子类 大小 情况
原文地址:https://www.cnblogs.com/jalja365/p/13051586.html