学习笔记之深入浅出MFC 第8章 C++重要性质----基类与派生类:谈继承(Inheritance)
来源:互联网 发布:绝食 水 知乎 编辑:程序博客网 时间:2024/04/29 18:31
继承是C++最神秘而特有的性质。矩形是形,椭圆形是形,三角形也是形。苍蝇是昆虫,蜜蜂是昆虫,蚂蚁也是昆虫。人们习惯把相同的性质抽离出来,成立一个基类(base class),再从中衍化出派生类(derived class) 。所以,以形状为例,我们可以得到下面这样的类层次,从而进一步说明继承的原理:
我们接下来用程序来表现一下上面形状的继承性:
首先,定义基类形状,所有的类从这个类继承
class CShape; //形状
{
private:
int m_color;
public:
void setcolor( int color) { m_color = color; }
};
在基类中定义的是从它分出去的所有子类的共有属性,比如这里的颜色m_color,设置颜色setcolor,每一个子类都有这两个属性,而且都是同一个函数可以实现的。
接下来是第一级继承,从形状继承出矩形、椭圆形和三角形,因为这三个都是形状:
class CRect : public CShape //矩形是一种形状
{//它会继承m_color和setcolor()
public:
void display() { ... }
};
class CEllipse : public CShape //椭圆形是一种形状
{//它会继承m_color和setcolor()
public:
void display() { ... }
};
class CTriangle : public CShape //三角形是一种形状
{//它会继承m_color和setcolor()
public:
void display() { ... }
};
上面三种图形都是继承自形状基类,所以都具有m_color和setcolor()功能,这时所有形状的共性。但是,针对每一种形状,其绘图函数display()都是不一样的,所以display()是它们各自的特性,需要单独在每一个子类中声明。
那么,接下来子类还可以往下继承,比如正方形也是一种矩形,圆形也是一种椭圆形
class CSquare : public CRect //正方形是一种矩形
{
public:
void display() { ... }
};
class CCircle : public CEllipse //圆形是一种椭圆形
{
public:
void display() { ... }
};
于是,可以这么操作:
CSquare square;
CRect rect1, rect2;
CCircle circle;
square.setcolor(1); //令square.m_color = 1;
square.display(); //调用CSquare::disolay
rect1.setcolor(2); //令rect1.m_color = 2;
rect1.display(); //调用CRect::disolay
rect2.setcolor(3); //令rect2.m_color = 3;
rect2.display(); //调用CRect::disolay
circle.setcolor(4); //令circle.m_color = 4;
circle.display(); //调用CCircle::disolay
特别需要注意的是第一个和第四个,父类中有display()子类中也有display(),那么到底调用的是哪一个呢?上面注释中说明的很清楚,子类中有的调用的是子类的,子类中没有的调用的是父类的。这是多态性,后面我们会讲到的。
需要注意以下这些事实与问题:
(1)、所有的类都由CShape派生下来,所以它们都自然而然继承了CShape的成员,包括变量和函数。也就是说,所有的形状都“暗自”具备了m_color变量和setcolor函数。所谓的“暗自”,意思就是无法从各派生类的声明中直接看出来。
(2)、两个矩形对象rect1和rect2各有自己的m_color,但是关于setcolor函数却是共享相同的CRect::setcolor(其实更应该说是CShape::setcolor)。下面图表表示期间关系:
同一个函数如何处理不同的数据?为什么rect1.setcolor和rect2.setcolor明明都是调用CRect::setcolor(其实也就是CShape::setcolor),却能有条不紊地分别处理rect1.m_color和rect2.m_color?答案在于this指针。下一节看完this指针我们再回过头来看看这里是为什么。
(3)、display之所以不提升到基类中,是因为每一个子类的形状不同,所以每一个的display()其实是不一样的,如果是用继承的方法获得的display()每个子类都是完全一样的。
this指针
还记得上面第二点的困惑吗?两个矩阵对象rect1和rect2各有自己的m_color成员变量,但是rect1.setcolor和rect2.setcolor却都是调用的同一个成员函数CRect::setcolor,我们就困惑了,CRect::setcolor怎么处理不同对象的m_color呢?答案就是:成员函数有一个隐藏参数,名称为this指针。
当你调用:rect1.setcolor(2); //rect1是CRect对象
rect2.setcolor(3); //rect2是CRect对象
时,编译器实际上为你做出来的编码是:
CRect::setcolor(2, (CRect*)&rect1 );
CRect::setcolor(3, (CRect*)&rect2 );
多出来的参数就是所谓的this指针。也就是说,我们在调用继承自父类的函数的时候,调用的函数仍旧是父类的函数,但是在函数中会加上这是哪一个子类在调用的参数,这个参数就标明了当前调用的子类。
其实在每一个类定义中,都有一个这样被省略的指针:
class CShape
{
public:
void setcolor(int color) { m_color = color; }
};
被编译之后其实是这样的:
class CShape
{
public:
void setcolor(int color , (CShape*)this) { this-> m_color = color; }
};
- 学习笔记之深入浅出MFC 第8章 C++重要性质----基类与派生类:谈继承(Inheritance)
- 学习笔记之深入浅出MFC 第8章 C++重要性质-----类封装
- 学习笔记之深入浅出MFC 第8章 C++重要性质----虚拟函数与多态(Polymorphism)
- 学习笔记之深入浅出MFC 第8章 C++重要性质---异常处理(Exception Handing)
- 学习笔记之深入浅出MFC 第8章 C++重要性质---构造函数与析构函数
- 学习笔记之深入浅出MFC 第8章 C++重要性质---Template
- 学习笔记之深入浅出MFC 第8章 C++重要性质--- 执行期类型信息(RTTI)
- 学习笔记之深入浅出MFC 第8章 C++重要特性---类与对象大解剖(虚拟函数的实现方式)
- 学习笔记之深入浅出MFC 第8章 C++重要特性----静态变量(static)
- 深入浅出MFC学习笔记:(第一章:win32基本概念,第二章:C++的重要性质)
- 深入浅出MFC学习笔记:(第一章:win32基本概念,第二章:C++的重要性质)
- C++重要性质02:继承(Inheritance)
- 一步一步学习C++(类)之继承与派生
- 2.C++的重要性质(深入浅出MFC之读书笔记)
- MFC学习笔记(三)之基类、派生类
- 继承与派生类 学习笔记1
- 继承与派生类 学习笔记2
- 学习笔记之深入浅出MFC 第2讲 窗口类注册与窗口的诞生
- Python数据分析学习笔记一
- ERROR 1045 (28000): Access denied for user...错误的解决
- hdu2795Billboard
- boost::shared_ptr:传值还是传引用?
- 划分树
- 学习笔记之深入浅出MFC 第8章 C++重要性质----基类与派生类:谈继承(Inheritance)
- keras代码阅读-Activition层
- Java transient关键字
- CSS3圆角border-radius属性详解
- 汇编语言学习第九章-转移指令的原理
- uWSGI+Nginx+Django安装和配置
- 剑指offer-面试题54:表示数值的字符串
- HDU 5656 CA Loves GCD
- C++第4次作业