C++学习-继承和派生类(9)

作者:gzshun. 原创作品,转载请标明出处!
来源:http://blog.csdn.net/gzshun


这几篇博文非常的基础,基础得真不知道如何形容,如果您是大牛请略过,这只是一个C++最基础部分的总结罢了。
开始学习类的继承,其实这些以前都学过了,也都用过,只是最近用自己的例子与语言总结下来,把这些特性用非常容易的例子来说明。有些书经常把某些简单的知识复杂化,而且很罗嗦,浪费脑细胞,我只是把自己觉得最基础也最重要的部分提取出来而已。最近得抓紧时间了,需要学的东西太多了。
一、继承的概念
继承是面向对象语言的一个重要机制,通过继承可以在一个一般类的基础上建立新类。被继承的类成为基类,在基类上建立的新类称为派生类,太儿戏了,哈哈。
单继承:一个类只有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
{
...
};

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

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

继承方式 基类特性 派生类特性 公有继承(public) public public protected protected private 不可访问 私有继承(private) public private protected private private 不可访问 保护继承(protected) public protected protected protected private 不可访问
四、公有继承的例子
在公有继承中,
1.派生类的对象可以访问基类中的公有成员;
2.派生类的成员函数可以访问基类的公有成员和保护成员。

#include <iostream> using namespace std; class CAnimal { public: CAnimal(const char *name) : mName(name) {} string GetName() const { return mName; } protected: void SetName(const char *name) { mName.assign(name); } private: string mName; }; class CDog : public CAnimal { public: CDog(const char *name) : CAnimal(name) {} string GetDogName() const { return GetName(); } void SetDogName(const char *name) { SetName(name); } }; int main() { CDog dog("Tom"); cout << "小狗的名字是:" << dog.GetDogName() << endl; cout << "动物的名字是:" << dog.CAnimal::GetName() << endl; cout << endl; dog.SetDogName("Wali"); cout << "小狗的新名字是:" << dog.GetDogName() << endl; cout << "动物的新名字是:" << dog.CAnimal::GetName() << endl; cout << endl; cout << "小狗的名字是:" << dog.GetName() << endl; //正确, 派生类的对象可以调用基类的公有成员 // cout << dog.SetName("Cat"); //错误, 派生类的对象不能调用基类的保护成员 return 0; }
执行结果:

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

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

小狗的名字是:Wali


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

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

#include <iostream> using namespace std; class CAnimal { public: CAnimal(const char *name) : mName(name) {} string GetName() const { return mName; } protected: void SetName(const char *name) { mName.assign(name); } private: string mName; }; class CDog : private CAnimal { public: CDog(const char *name) : CAnimal(name) {} string GetDogName() const { return GetName(); } void SetDogName(const char *name) { SetName(name); } }; int main() { CDog dog("Tom"); cout << "小狗的名字是:" << dog.GetDogName() << endl; // cout << "动物的名字是:" << dog.CAnimal::GetName() << endl; cout << endl; dog.SetDogName("Wali"); cout << "小狗的新名字是:" << dog.GetDogName() << endl; // cout << "动物的新名字是:" << dog.CAnimal::GetName() << endl; cout << endl; // cout << "小狗的名字是:" << dog.GetName() << endl; // cout << dog.SetName("Cat"); return 0; }
执行结果:

小狗的名字是:Tom

小狗的新名字是:Wali


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

七、对上述例子的总结

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

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

八、友元关系与继承

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

#include <iostream> using namespace std; class CBase { public: friend class CFriend; private: int mBase; }; class CDerived : public CBase { private: int mDerived; }; class CFriend { public: int GetVal(CBase b) const { return b.mBase; } int GetVal1(CDerived d) const { return d.mBase; } // int GetVal2(CDerived d) const // { // return d.mDerived; // } }; int main() { return 0; }
被注释掉的是错误的,不能访问派生类中自己的部分成员,而可以访问派生类中属于基类的部分成员。


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

#include <iostream> using namespace std; class CBase { public: void Print() const { cout << "CBase: mStatic = " << mStatic << endl; } static int mStatic; }; int CBase::mStatic = 2; class CDerived : public CBase { public: void Print() const { cout << "CDerived: mStatic = " << mStatic << endl; } }; int main() { CBase base; CDerived derived; base.Print(); derived.Print(); cout << endl; base.mStatic = 4; base.Print(); derived.Print(); return 0; }
执行结果:

CBase: mStatic = 2
CDerived: mStatic = 2

CBase: mStatic = 4
CDerived: mStatic = 4


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

#include <iostream> using namespace std; class CBase { public: CBase() { cout << "调用基类的构造函数" << endl; } ~CBase() { cout << "调用基类的析构函数" << endl; } }; class CDerived : public CBase { public: CDerived() { cout << "调用派生类的构造函数" << endl; } ~CDerived() { cout << "调用派生类的析构函数" << endl; } }; int main() { CDerived obj; return 0; }
执行结果:

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

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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值