C++之继承篇

来源:互联网 发布:just do it 乔丹 编辑:程序博客网 时间:2024/05/22 11:52

1.继承权限

继承权限与访问权限 public(公有访问)protected(保护访问)private(私有访问)public(公有继承)继承后变成public(公有访问)继承后变成protected(保护访问)继承后不可访问protected(保护继承)继承后变成protected(保护访问)继承后变成protected(保护访问)继承后不可访问private(私有继承)继承后变成private(私有访问)继承后变成private(私有访问)继承后不可访问

注:protected和private的区别:

                                         protected:在派生类中可以访问,类外不可访问

                                          private:派生类和类外均不可访问


2.继承定义格式

    

3.同名隐藏

  定义:基类,派生类某一个成员变量同名,或者某一个成员函数同名(只要函数名一样,不管参数列表,返回值是否一样),通过派生类调用该成员变量或成员函数时,只会调用派生类的,基类的看不到,这种现象称为同名隐藏。

#include <iostream>#include <windows.h>using namespace std;class Base{public:int _pub; void Fun1(){cout<<"Base::void Fun1()"<<endl;} void Fun2(int){cout<<"Base::void Fun2(int)"<<endl;}int Fun3(){cout<<"Base::int Fun3()"<<endl;return 0;}};class Derived:public Base{public:int _pub; void Fun1(){cout<<"Derived::Fun"<<endl;} void Fun2()//与Base中Fun2相比不带参数{cout<<"Derived::void Fun2(int)"<<endl;}void Fun3()//与Base中Fun3相比返回值不同{cout<<"Derived::void Fun3()"<<endl;}};int main(){    Derived d;  Base b;  b._pub=1;  d._pub=2;  cout<<d._pub<<endl;  d.Fun1();  d.Fun2();  d.Fun3();    system("pause");  return 0;}

结果:


4.对象模型



测试代码:

#include <iostream>#include <windows.h>using namespace std;class Base{public:int _pub;int _pro;int _pri;};class Derived:public Base{public:int _pub1;};int main(){    Derived d;  Base b;  b._pub=1;  b._pro=2;  b._pri=3;  d._pub1=4;  d._pub=5;  d._pro=6;  d._pri=7;  system("pause");  return 0;}


总结:基类的对象模型是按照声明次序的。派生类是先是基类的,然后是自己的(按照声明顺序排列)。

5.派生类对象

class Base{public:Base(){cout<<"Base::Base()"<<endl;}~Base(){cout<<"Base::~Base()"<<endl;}private:int _pub;int _pro;int _pri;};class Derived:public Base{public:   Derived()   {   cout<<"Derived::Derived()"<<endl;   }    ~Derived()   {   cout<<"Derived::~Derived()"<<endl;   }private:int _pub1;};
定义一个派生类对象
Derived  d;
d的调用顺序为:Derived()->~Derived()
  实际执行顺序:Base() ->Derived()-> ~Derived()->~Base()
小结:
   (1)基类有缺省构造函数,派生类无构造函数,系统会给派生类自动合成
   (2)基类无构造函数,派生类无构造函数,系统不会给基类,派生类自动合成
     (3)基类构造函数有参数,派生类必须定义构造函数,并在初始化列表显示调用基类的构造函数
6.赋值兼容规则-----public继承
   
#include <iostream>#include <windows.h>using namespace std;class Base{public:int _b;};class Derived:public Base{public:   int _d;};int main(){  Base b;  Derived d;  b=d;  d=b;  Base &b1=d;  Base *p=&d;  Derived &d=b;  Derived * p1=&b;  }

小结:
   (1)子类对象可以赋值给父类对象。原理就像是切片/切割一样。
  (2)父类对象不能赋值给子类对象。
  (3)父类的指针/引用可以指向子类对象。
  (4)子类的指针/引用不能指向父类对象。
7.友元函数&Static&继承
 友元函数属于类外函数,所以不能继承。
 static修饰的成员可以继承,但是,无论多少派生类,只有一份Static修饰的成员。
8.多继承
如: 有class A,class B, 
     class C:public A,public B
   C类的父类有两个,便成C类为多继承。
注:继承多个类时,每个类的继承权限不能省略,否则,class默认的继承权限是private。
9.菱形继承
#include <iostream>#include <windows.h>using namespace std;class B{public:int _b;};class C1:public B{public:int _c1;};class C2:public B{public:int _c2;};class D:public C1,public C2{public:int _d;};int main(){  D d;  d.C1::_b;  d._c1;  d.C2::_b;  d._c2;  d._d ;  system("pause");  return 0;}


注:D类对象访问_b时,需要加上作用域,不然会产生二义性。因为C1,C2类各有一个_b,D类对象访问时,不知要访问哪个。

10.虚继承---解决菱形继承的二义性和数据冗余的问题

继承权限前面加上virtual关键字。

例如:

class A{public:int _a;};class B:virtual public A{public:int _b;};int main(){B b;b._a=1;b._b=2; return 0;}


小结:

(1)虚继承中,在程序编译时,偏移量的表格已经生成。在调用构造函数时,只是将地址存入。

(2)虚继承中,A类若是无构造函数,B类自动合成构造函数。(将指向偏移量的地址存入对象的前四个字节)。

(3)虚继承与普通继承的区别在于,调用构造函数前,先PUSH 1,以此来判断是否为虚继承,若是,便执行(2)中所说。

(4)虚继承中,基类的成员变量只存在一份,所以当派生类对象调用基类对象时,不会存在二义性问题,因此,虚继承可以解决菱形继承中的二义性问题和数据冗余的问题。


用虚继承解决菱形继承中二义性问题:

#include <iostream>#include <windows.h>using namespace std;class B{public:int _b;};class C1:virtual public B{public:int _c1;};class C2:virtual public B{public:int _c2;};class D:public C1,public C2{public:int _d;};int main(){  D d;  d._b=1;  d._c1=2;  d._c2=3;  d._d =4;  system("pause");  return 0;}




注意: 是C1和C2虚继承B类,所以只在这前面加virtual关键词。

下面举一个在不同位置加VIRTUAL关键词,看会引起什么不同

#include <iostream>#include <windows.h>using namespace std;class B{public:int _b;};class C1: public B{public:int _c1;};class C2: public B{public:int _c2;};class D:virtual public C1,virtual public C2{public:int _d;};int main(){  D d;  d.C1::_b=1;  d._c1=2;  d.C2::_b=5;  d._c2=3;  d._d =4;  system("pause");  return 0;}


上述的这种情况,并没有解决菱形二义性的问题。

                                             
1 0
原创粉丝点击