C++之类的继承

1 继承与派生

        前几天讲了类的构造函数和析构函数,今天跟大家学习一下类的继承的知识。

        继承是面向对象程序设计中最重要的机制。通过继承机制,可以利用已经有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有自己新定义的成员,而且还同时拥有旧的成员。通常把被继承的类称为基类或父类,继承它的类称为派生类或子类。

        下面我们给一个简单的例子,让大家了解一下类的继承如何实现。

  1: #include <iostream>   
  2: using namespace std;   
  3:  
  4: //基类 父类 
  5: class CBase   
  6: {   
  7: public: 
  8:     CBase() 
  9:     { 
 10:         mCounter=0; 
 11:     } 
 12:     ~CBase() 
 13:     { 
 14:          
 15:     } 
 16:     void setCounter(int values) 
 17:     { 
 18:         mCounter=values; 
 19:     } 
 20:     int getCounter() 
 21:     { 
 22:         return mCounter; 
 23:     } 
 24:  
 25: public: 
 26:     int mCounter; 
 27: };   
 28: //派生类 子类 
 29: class CChild:public CBase 
 30: { 
 31:      
 32: }; 
 33:  
 34: int main()   
 35: {   
 36:     CChild child; 
 37:     //子类继承了父类的函数 
 38:     child.setCounter(123); 
 39:     cout<<child.getCounter()<<endl; 
 40:     return 0;   
 41: } 
 42:  
 43: 

我们定义了一个父类Cbase,然后定义了它的子类CChild虽然子类里什么也没写,但是它还是继承了父类里的setCounter方法和getCounter方法。

2 常用的继承关系

        不知道各位注意没有,子类在继承父类的时候,使用了public关键字,表示公有继承。剩余的继承关系还有私有继承保护继承。公有继承是最常用的继承方式,而私有继承就比较少用,保护继承就更少用了。下面我们分别来讲解一下这些继承方式。

2.1 公有继承(public)

        写继承代码时,在基类前面加上关键字public表示公有继承。公有继承的特点:

    • 子类(派生类)的成员函数可以访问基类中的公有成员和保护成员。
    • 子类(派生类)的对象可以访问基类中的公有成员。

        为了让大家能够清楚地了解公有继承的特点,复制一下下面的代码,亲自试一试吧。

  1: #include <iostream>   
  2: using namespace std;   
  3:  
  4: class A 
  5: { 
  6: public: 
  7:     A() 
  8:     { 
  9:         mPublic=1; 
 10:         mProtected=2; 
 11:         mPrivate=3; 
 12:     } 
 13:     ~A(){} 
 14:     void speak() 
 15:     { 
 16:  
 17:     } 
 18:     int mPublic; 
 19: private: 
 20:     int mPrivate; 
 21: protected: 
 22:     int mProtected; 
 23: }; 
 24:  
 25: class B:public A 
 26: { 
 27: public: 
 28:     B(){} 
 29:     ~B(){} 
 30:     void talk() 
 31:     { 
 32:         a=mPublic; 
 33:         b=mProtected; 
 34:         c=mPrivate;//注意这个位置 
 35:         cout<<a<<" "<<b<<""<<c<<endl; 
 36:     } 
 37: private: 
 38: int a,b,c; 
 39: }; 
 40:  
 41: int main()   
 42: {   
 43:     B b; 
 44:     b.talk(); 
 45:     int x=b.mPublic; 
 46:     int y=b.mProtected;//注意这个位置 
 47:     int z=b.mPrivate;//注意这个位置 
 48:     return 0;   
 49: } 
 50: 

编译一下上面的代码,看看你会得到什么答案。不出意外,结果是这样的:

    • Error    1    error C2248: 'A::mPrivate' : cannot access private member declared in class 'A'    e:\XXX\main.cpp    34
    • Error    2    error C2248: 'A::mProtected' : cannot access protected member declared in class 'A'    e:\XXX\main.cpp    46
    • Error    3    error C2248: 'A::mPrivate' : cannot access private member declared in class 'A'    e:\XXX\main.cpp    47

这三个错误还是很好理解的吧,看看公有继承的特点就明白了。派生类B的成员函数talk不能访问基类A的私有变量mPrivate;派生类B只能访问基类A的公有成员mPublic。

2.2 私有继承(private)

        写继承代码时,在基类前面加上关键字private表示私有继承。如果子类继承父类时不使用关键字,则默认是私有继承。私有继承的特点:

    • 基类的成员只能有直接派生类访问。
    • 派生类从基类继承来的成员不能再往下派生。
    • 积累的公有成员个保护成员都作为派生类的私有成员。
    • 对派生类对象而言,所有基类对象的成员都是不可见的。
2.3 保护继承(protected)

        写继承代码时,在基类前面加上关键字protected表示保护继承。保护继承的特点:

    • 基类的成员只能由直接派生类访问。
    • 派生类从基类继承来的成员不能再往下派生。
    • 积累的公有成员个保护成员都作为派生类的保护成员,且不能被派生类的子类访问。
    • 对派生类对象而言,所有基类对象的成员都是不可见的。

3 在继承关系中构造函数、析构函数的调用顺序

        类对象在初始化时,会先调用父类的构造函数,然后调用自己的构造函数;类对象在析构时,先调用自己的析构函数,再调用父类的析构函数。例如:

  1: #include <iostream>   
  2: using namespace std;   
  3:  
  4: class A 
  5: { 
  6: public: 
  7:     A(){cout<<"This is A constructor."<<endl;} 
  8:     ~A(){cout<<"This is A destructor."<<endl;} 
  9: }; 
 10:  
 11: class B:public A 
 12: { 
 13: public: 
 14:     B(){cout<<"This is B constructor."<<endl;} 
 15:     ~B(){cout<<"This is B destructor."<<endl;} 
 16: }; 
 17:  
 18: class C:public B 
 19: { 
 20: public: 
 21:     C(){cout<<"This is C constructor."<<endl;} 
 22:     ~C(){cout<<"This is C destructor."<<endl;} 
 23: }; 
 24:  
 25: int main()   
 26: {   
 27:     C *p=new C(); 
 28:     delete p; 
 29:     p=NULL; 
 30:     return 0;   
 31: } 
 32: 

运行结果如下:

2011-07-01_223852

4 多继承

        C++不同于Java,它支持多继承,即一个派生类有多个基类。基本格式如下:

  1: class A 
  2: { 
  3: public: 
  4:     A(){cout<<"This is A constructor."<<endl;} 
  5:     ~A(){cout<<"This is A destructor."<<endl;} 
  6: }; 
  7:  
  8: class B 
  9: { 
 10: public: 
 11:     B(){cout<<"This is B constructor."<<endl;} 
 12:     ~B(){cout<<"This is B destructor."<<endl;} 
 13: }; 
 14:  
 15: class C:public A,public B 
 16: { 
 17: public: 
 18:     C(){cout<<"This is C constructor."<<endl;} 
 19:     ~C(){cout<<"This is C destructor."<<endl;} 
 20: };

看到这,大家可能会产生好奇,如果可以这么定义,那么构造函数和析构函数的调用顺序会是什么样?大家不妨回去自己试一试,可以把这个当作家庭作业哟。这个问题我们会在以后的文章中讲解。

感谢:《C++编程关键路径——程序员求职指南》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值