学习继承和派生类

  一、继承的概念
继承是面向对象语言的一个重要机制,通过继承可以在一个一般类的基础上建立新类。被继承的类成为基类,在基类上建立的新类称为派生类,太儿戏了,哈哈。
单继承:一个类只有1个基类
多继承:一个类有2个或2个以上的基类


二、继承的格式
1.单继承

class <派生类名> : <继承方式> <基类名>
{
<派生类的成员>
};
2.多继承
class <派生类名> : <继承方式1> <基类名1>, <继承方式2> <基类名2>
{
<派生类的成员>
};
3.补充--默认继承的保护级别
a.class关键字定义的派生类默认是private继承
b.struct关键字定义的派生类默认是public继承
这与之前介绍过的class与struct的区别是一样的,在struct声明类中,默认是public访问级别,而class声明的类中,默认是private访问级别。
class的例子:
下面继承的关系等价于:class CDerived : private CBase
class CBase
{
...
};
class CDerived : CBase
{
...
};

struct的例子:
下面继承的关系等价于:struct CDerived : public CBase
struct CBase
{
...
};
struct CDerived : CBase
{
...
};

三、不同继承方式的基类特性与派生类特性

下面给一个表,是一个继承的规则,基本上必须要熟记,用几次就熟练了。

  1. 继承方式            基类特性        派生类特性  
  2. 公有继承(public)    public          public  
  3.                     protected       protected  
  4.                     private         不可访问  
  5.   
  6. 私有继承(private)   public          private  
  7.                     protected       private  
  8.                     private         不可访问  
  9.   
  10. 保护继承(protected) public          protected  
  11.                     protected       protected  
  12.                     private         不可访问  

四、公有继承的例子
在公有继承中,
1.派生类的对象可以访问基类中的公有成员;
2.派生类的成员函数可以访问基类的公有成员和保护成员。

  1. #include <iostream>   
  2.   
  3. using namespace std;  
  4.   
  5. class CAnimal  
  6. {  
  7. public:  
  8.     CAnimal(const char *name) : mName(name) {}  
  9.     string GetName() const  
  10.     {  
  11.         return mName;  
  12.     }  
  13. protected:  
  14.     void SetName(const char *name)  
  15.     {  
  16.         mName.assign(name);  
  17.     }  
  18. private:  
  19.     string mName;  
  20. };  
  21.   
  22. class CDog : public CAnimal  
  23. {  
  24. public:  
  25.     CDog(const char *name) : CAnimal(name) {}  
  26.     string GetDogName() const  
  27.     {  
  28.         return GetName();  
  29.     }  
  30.     void SetDogName(const char *name)  
  31.     {  
  32.         SetName(name);  
  33.     }  
  34. };  
  35.   
  36. int main()  
  37. {  
  38.     CDog dog("Tom");  
  39.     cout << "小狗的名字是:" << dog.GetDogName() << endl;  
  40.     cout << "动物的名字是:" << dog.CAnimal::GetName() << endl;  
  41.     cout << endl;  
  42.   
  43.     dog.SetDogName("Wali");  
  44.     cout << "小狗的新名字是:" << dog.GetDogName() << endl;  
  45.     cout << "动物的新名字是:" << dog.CAnimal::GetName() << endl;  
  46.     cout << endl;  
  47.   
  48.     cout << "小狗的名字是:" << dog.GetName() << endl; //正确, 派生类的对象可以调用基类的公有成员   
  49. //    cout << dog.SetName("Cat"); //错误, 派生类的对象不能调用基类的保护成员   
  50.     return 0;  
  51. }  

执行结果:

小狗的名字是:Tom
动物的名字是:Tom

小狗的新名字是:Wali
动物的新名字是:Wali

小狗的名字是:Wali


五、私有继承的例子
在私有继承中,
1.派生类的对象不可以访问基类中的所有成员;
2.派生类的成员函数可以访问基类的公有成员和保护成员。

以下的例子跟公有继承的例子差不多,只是将几行代码给注释掉了,被注释掉的都是因为private方式的继承不能调用成功,都是错误的。

  1. #include <iostream>   
  2.   
  3. using namespace std;  
  4.   
  5. class CAnimal  
  6. {  
  7. public:  
  8.     CAnimal(const char *name) : mName(name) {}  
  9.     string GetName() const  
  10.     {  
  11.         return mName;  
  12.     }  
  13. protected:  
  14.     void SetName(const char *name)  
  15.     {  
  16.         mName.assign(name);  
  17.     }  
  18. private:  
  19.     string mName;  
  20. };  
  21.   
  22. class CDog : private CAnimal  
  23. {  
  24. public:  
  25.     CDog(const char *name) : CAnimal(name) {}  
  26.     string GetDogName() const  
  27.     {  
  28.         return GetName();  
  29.     }  
  30.     void SetDogName(const char *name)  
  31.     {  
  32.         SetName(name);  
  33.     }  
  34. };  
  35.   
  36. int main()  
  37. {  
  38.     CDog dog("Tom");  
  39.     cout << "小狗的名字是:" << dog.GetDogName() << endl;  
  40. //    cout << "动物的名字是:" << dog.CAnimal::GetName() << endl;   
  41.     cout << endl;  
  42.   
  43.     dog.SetDogName("Wali");  
  44.     cout << "小狗的新名字是:" << dog.GetDogName() << endl;  
  45. //    cout << "动物的新名字是:" << dog.CAnimal::GetName() << endl;   
  46.     cout << endl;  
  47.   
  48. //    cout << "小狗的名字是:" << dog.GetName() << endl;   
  49. //    cout << dog.SetName("Cat");   
  50.     return 0;  
  51. }  

执行结果:

小狗的名字是:Tom

小狗的新名字是:Wali


六、保护继承的例子
保护继承的例子跟私有继承的例子是一样的,规则差不多。
在保护继承中,
1.派生类的对象不可以访问基类中的所有成员;
2.派生类的成员函数可以访问基类的公有成员和保护成员。

七、对上述例子的总结

派生类对象和派生类中的成员函数对基类的访问不同。
在公有继承中,
1.派生类的对象可以访问基类中的公有成员
2.派生类的成员函数可以访问基类的公有成员和保护成员。

在私有继承和保护继承中,
1.派生类的对象不可以访问基类中的所有成员
2.派生类的成员函数可以访问基类的公有成员和保护成员。

八、友元关系与继承

友元关系不能被继承。基类的友元对派生类的成员没有特殊访问权限,例如在CBase中声明了一个友元类CFriend,由CBase类派生出CDerived类,在CFriend类中,可以访问基类CBase中的所有成员和派生类CDerived中属于CBase部分的成员,看例子:

  1. #include <iostream>   
  2.   
  3. using namespace std;  
  4.   
  5. class CBase  
  6. {  
  7. public:  
  8.     friend class CFriend;  
  9. private:  
  10.     int mBase;  
  11. };  
  12.   
  13. class CDerived : public CBase  
  14. {  
  15. private:  
  16.     int mDerived;  
  17. };  
  18.   
  19. class CFriend  
  20. {  
  21. public:  
  22.     int GetVal(CBase b) const  
  23.     {  
  24.         return b.mBase;  
  25.     }  
  26.     int GetVal1(CDerived d) const  
  27.     {  
  28.         return d.mBase;  
  29.     }  
  30. //    int GetVal2(CDerived d) const   
  31. //    {   
  32. //        return d.mDerived;   
  33. //    }   
  34. };  
  35.   
  36. int main()  
  37. {  
  38.     return 0;  
  39. }  

被注释掉的是错误的,不能访问派生类中自己的部分成员,而可以访问派生类中属于基类的部分成员。


九、静态成员与继承
之前说过,在一个类的所有对象中,静态成员只保存了一个副本,不属于对象的成员,所有对象共享同一个static成员。
在继承过程中,原理也是一样。若基类定义了static成员,则在整个继承层次中只有一个静态成员。所以无论从基类派生出多少个派生类,声明了多少对象,每个static成员只有一个实例。
看个例子:

  1. #include <iostream>   
  2.   
  3. using namespace std;  
  4.   
  5. class CBase  
  6. {  
  7. public:  
  8.     void Print() const  
  9.     {  
  10.         cout << "CBase: mStatic = " << mStatic << endl;  
  11.     }  
  12.     static int mStatic;  
  13. };  
  14.   
  15. int CBase::mStatic = 2;  
  16.   
  17. class CDerived : public CBase  
  18. {  
  19. public:  
  20.     void Print() const  
  21.     {  
  22.         cout << "CDerived: mStatic = " << mStatic << endl;  
  23.     }  
  24. };  
  25.   
  26. int main()  
  27. {  
  28.     CBase base;  
  29.     CDerived derived;  
  30.   
  31.     base.Print();  
  32.     derived.Print();  
  33.     cout << endl;  
  34.   
  35.     base.mStatic = 4;  
  36.     base.Print();  
  37.     derived.Print();  
  38.   
  39.     return 0;  
  40. }  

执行结果:

CBase: mStatic = 2
CDerived: mStatic = 2

CBase: mStatic = 4
CDerived: mStatic = 4


十、继承过程中,构造函数与析构函数的调用
派生类与基类的构造函数和析构函数的调用顺序,写个小例子便可知分晓:

  1. #include <iostream>   
  2.   
  3. using namespace std;  
  4.   
  5. class CBase  
  6. {  
  7. public:  
  8.     CBase()  
  9.     {  
  10.         cout << "调用基类的构造函数" << endl;  
  11.     }  
  12.     ~CBase()  
  13.     {  
  14.         cout << "调用基类的析构函数" << endl;  
  15.     }  
  16. };  
  17.   
  18. class CDerived : public CBase  
  19. {  
  20. public:  
  21.     CDerived()  
  22.     {  
  23.         cout << "调用派生类的构造函数" << endl;  
  24.     }  
  25.     ~CDerived()  
  26.     {  
  27.         cout << "调用派生类的析构函数" << endl;  
  28.     }  
  29. };  
  30.   
  31. int main()  
  32. {  
  33.     CDerived obj;  
  34.     return 0;  
  35. }  

执行结果:

调用基类的构造函数
调用派生类的构造函数
调用派生类的析构函数
调用基类的析构函数

顺序是:基类的构造函数 -> 派生类的构造函数 -> 派生类的析构函数 -> 基类的析构函数


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值