一、继承的相关基本概念

1、继承的定义

    在C++中,可以使用继承来使新类得到已定义的一些类中的特性,这就好比与孩子从父亲母亲得到遗传类似,所以我们称原有的类为基类或父类,用原有类来生成新的类的过程称为派生,所以生成的新类称之为派生类或者子类。

2、 继承的声明

     在继承中和上面所说的遗传是有区别的,孩子只能遗传其父母的一些基因,而在C++的继承中,一个新的类是可以继承多个不同的类,被称为多重继承。所以继承分为单继承和多继承。
     继承的定义格式如下:
        
 
   在一个类中,我们知道其成员的访问类型分为三种,公有(public),保护(protected)和私有(private)。相应的继承方式也分为这三种,他们的区别也就在于派生类的成员和类外对象在访问它从基类继承来的的成员的访问权限不同。
   关于三种继承方式后的成员访问权限变换关系如下表所示:
      
          
       其实这个表我自己是看着很烦,其实很容易记的,根本就不需要看这个表的。你只要记得基类的private成员在派生类中始终是不可访问的,然后记着private>protected>public,高访问权限的继承方式会改变低的访问权限成员的访问权限。说起来还是比较绕口,其实并不需要记,你看一遍肯定会牢记在心的,不信你试试看。
       可以看出来,不管是哪一种继承方式,在派生类内都可以访问基类的非私有成员,基类的私有成员虽然被继承了,但是并不是可见的。而对于保护和私有继承方式,类外对象并不能访问基类的成员,公有继承方式下可以访问基类的公有成员。

二、构造函数和析构函数

      在派生类中,从基类继承而来的成员初始化需要调用基类的构造函数,派生类中新增的成员初始化则调用自己的构造函数。   

1.继承中的构造函数

      这里,当基类没有定义自己的构造函数,则在派生类中也可以不用定义,在构造对象时自行调用默认构造函数,但一般在编译器里会认为构造函数并不做什么事情所以对代码进行优化,并不生成默认构造函数,当你在转到反汇编看汇编代码的时候是看不到调用构造函数的语句的。
      当基类显式地定义了自己的构造函数,则编译器为派生类生成默认构造函数,而且当基类没有缺省的构造函数的时候,就必须为派生类定义构造函数且在初始化列表中显式的给出基类名和其参数列表,不然在派生过程中编译器就不知道如何调用基类构造函数。
 
      上面这两点其实与在类中包含另一个类的对象的情况差不多,我们也很容易理解。那么派生类到底能不能继承基类的构造函数呢?
       这一点很多人说法都不一样,有人说派生类继承了基类的构造函数,因为你在构造一个派生类对象的时候会调用基类的构造函数。其实准确的说应该是带引号的继承,之所以能够调用基类的构造函数,是因为编译器使基类的构造函数在派生类中可见,在创建派生类的对象时会先调用基类的构造函数。  
构造函数的调用顺序:
     因为在创建派生类对象的时候,要先给它继承基类的成员,所以当程序走到派生类的构造函数的时候会先调用基类的构造函数,所以对于构造函数的调用顺序,是按照继承列表的顺序依次调用每一个基类的构造函数,然后调用派生类自己的构造函数,再执行它的函数体。当然如果派生类中还有别的类对象,则先调用此对象类的构造函数再调用派生类自己的构造函数。
        

2.继承中的析构函数

        析构函数是不能被继承的,同时一般会把基类的析构函数定义成虚析构函数:
 class Base
{
public:
Base(){}
virtual ~Base()
{
cout << "~Base()" << endl;
}
public:
int _pub1;
};
class Derived:public Base
{
public:
Derived(int k=)
{
buf = new char[k];
}
~Derived()
{
delete[] buf;
cout << "~Derived()" << endl;
}
public:
char* buf;
}; void test()
{ Base* b = new Derived();
delete b;
}
int main()
{
test();
return ;
}
如果不定义成虚函数,在delete时只会调用基类的析构函数而不会调用派生类的析构函数而导致内存泄漏。虚函数在这里不细讲了。
析构函数的调用顺序:
 析构函数的调用情况,我们一般认为和压栈类似,所以析构函数的调用顺序如下:
        

三、继承中的同名隐藏

        在C++中我们知道有重载,当在同一作用域内函数名相同且函数的参数列表不同,就会构成重载,这样就可以根据传参的不同来调用相应的函数,而不会存在二义性。
        但是在派生类中如果有一个和基类中同名的函数,那么在派生类中基类的这个函数就是被屏蔽的,当你用派生类对象调用这个函数一定是调用派生类中的函数,即使两个函数的参数列表不同。但其实基类的这个函数还是被继承了的,要想调用可以使用作用域解析符进行调用。(对于一个同名的成员也是同样的道理)。例子如下:
 
 class A
{
public:
void test(int)
{
cout << "test1()" << endl;
} public:
int _pub1;
protected:
int _pro1;
private:
int _pri1;
}; class B :public A
{
public:
void test()
{
cout << "test2()" << endl;
}
public:
int _pub2;
protected:
int _pro2;
private:
int _pri2;
};
int main()
{
B b;
b.test(); //编译错误
b.test(); //编译错误
b.A::test(); //正确
return ;
}
四、继承中的赋值兼容规则
    在此之前,我们看看基类和派生类的对象模型:
 class Base
{
public:
Base() { cout << "Base()" << endl; }
~Base() { cout << "~Base()" << endl; }
public:
int _pub1;
protected:
int _pro1; };
class Derived :public Base
{
public:
Derived() { cout << "Derived()" << endl; }
~Derived() { cout << "~Derived()" << endl; }
public:
int _pub2;
protected:
int _pro2;
};
int main()
{
return ;
}
假如就这样定义基类和派生类,那么派生类继承了基类的_pub1和pro1成员
    
赋值兼容规则如下:
1、派生类对象可以直接赋值给基类对象
      基类对象不能赋值给派生类对象
2、基类类型指针可以指向派生类对象(派生类对象可以初始化基类的引用)
      派生类类型指针不可以指向基类对象
这里也比较容易理解(当然是在public继承下),一个派生类对象本来就是从它的基类继承而来的,向上图中的对象模型,在派生类中有与基类对应的一个模块是继承来的成员,那么在赋值过程中编译器是可以把相应的基类部分赋值给基类对象。而对于把一个基类对象赋值给派生类对象的话,

五、理解“is a”和“has a”

     我一开始就很不理解为啥要总结这么样的关系,还这么抽象,什么东西啊。后来写写代码也确实慢慢领会了一点,还是有那吗一丝丝韵味在其中的。
is a:
     is a就是有一个,对于public继承,就有着is a特性。在上面的赋值兼容规则中也说到了,一个派生类对象时可以赋值给基类对象的,所以派生类可以代替任何需要直接基类的地方。is a就是代表了这种继承关系。对于多继承或者在派生类对象中有新增加的东西,这种关系相当于is like。
has a:
     has a一般用来描述是组合这种关系的,就是在某一个类中有另一个类。那么在这个类中就可以用它包含的类的成员及成员函数,有时候我们可以把保护和私有继承也看成是一种has a关系,因为只有在类内才可以访问基类的成员。
     is a相当于父亲在儿子家干活,而has a相当于雇别人在家里干活。大概就是这么个意思,大家能理解就行了,对于组合和继承这里就不展开讲了,它们各有优缺点和用武之地。在我们利用继承的时候,并不是说我们需要在这个类中使用另一个类的某些东西就继承它,要保证这个类是和基类是有is a关系的,比如说老虎是动物的一种,这才叫继承。
      
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

C++的三大特性之一继承的更多相关文章

  1. java提高篇(二)-----理解java的三大特性之继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  2. 黑马程序员——OC语言 三大特性之继承

    Java培训.Android培训.iOS培训..Net培训.期待与您交流! (以下内容是对黑马苹果入学视频的个人知识点总结) 三大特性之继承 (一)继承的基本用法 先建立个Animal再用Dog继承前 ...

  3. java提高篇(二)-----理解java的三大特性之继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  4. (转)java提高篇(二)-----理解java的三大特性之继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  5. 浅谈python的对象的三大特性之继承

    前面我们定义了人的类,并用这个类实例化出两个人jack和lily,查看了它们的内存空间. 现在我们再来看看类中所存在的对向对象编程的三大特性之继承的一些特性. 前面定义了一个人的类,可是我们还知道,人 ...

  6. java基础(二)-----java的三大特性之继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  7. 【转】java提高篇(二)-----理解java的三大特性之继承

    [转]java提高篇(二)-----理解java的三大特性之继承 原文地址:http://www.cnblogs.com/chenssy/p/3354884.html 在<Think in ja ...

  8. python基础学习Day17 面向对象的三大特性之继承、类与对象名称空间小试

    一.课前回顾 类:具有相同属性和方法的一类事物 实例化:类名() 过程: 开辟了一块内存空间 执行init方法 封装属性 自动的把self返回给实例化对象的地方 对象:实例 一个实实在在存在的实体 组 ...

  9. C++三大特性之继承

    原文地址:https://qunxinghu.github.io/2016/09/12/C++%20%E4%B8%89%E5%A4%A7%E7%89%B9%E6%80%A7%E4%B9%8B%E7%B ...

  10. Java学习笔记二十一:Java面向对象的三大特性之继承

    Java面向对象的三大特性之继承 一:继承的概念: 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类. 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方 ...

随机推荐

  1. HDU 5606 tree 并查集

    tree 把每条边权是1的边断开,发现每个点离他最近的点个数就是他所在的连通块大小. 开一个并查集,每次读到边权是0的边就合并.最后Ans​i​​=size[findset(i)],size表示每个并 ...

  2. 配置Git自动补全功能

    Git装好后,默认是不会有按tab补全命令的功能的.可如下配置: 去git的源码中,找到contrib/completion/git-completion.bash 将git-completion.b ...

  3. (一)NUnit单元测试心得

    由于各种缘由,一本<.Net单元测试艺术>突然出现在了我的办公桌上,于是我的单元测试之路就此开始.通过一两个月不间断的学习,以及不断结合具体的项目做开发,再结合书上的知识对单元测试有了一些 ...

  4. 手把手教你写对拍程序(PASCAL)

    谁适合看这篇文章? ACMERS,OIERS或其它参加算法竞赛或需要算法的人 对操作系统并不太熟悉的人 不会写对拍的人 在网上找不到一个特别详细的对拍样例的人 不嫌弃我写的太低幼的人 前言 在NOIP ...

  5. 【译】 AWK教程指南 8处理多行数据

    awk 每次从数据文件中只读取一行数据进行处理.awk是依照其内置变量 RS(Record Separator) 的定义将文件中的数据分隔成一行一行的Record.RS 的默认值是 "\n& ...

  6. 项目用到了lua的哪些部分

    昨天有位同事跟我说,我们的手游客户端(cocos2d-x lua binding)代码没有看到lua的特殊技巧,用起来跟其他语言差不多.<Programming in lua>毕竟有将近4 ...

  7. Morris Traversal

    昨天临近要睡觉的时候做了一个leetcode题目,"Recover BST",算法很容易就想到了,直接找出两个异常点就好了,但是我写的算法是用栈实现的非递归遍历,空间复杂度是O(N ...

  8. 谈谈Nginx有哪些特点

    1.热部署        我个人觉得这个很不错.在master管理进程与worker工作进程的分离设计,使的Nginx具有热部署的功能,那么在7×24小时不间断服务的前提下,升级Nginx的可执行文件 ...

  9. Ext.useShims=true

    Extjs的panel中嵌套ActiveX的插件,如PDF,但是Ext控件被遮罩 eg.在panel的tbar中加入下拉框,结果其下拉值看不到,原因就是被PDF给遮住了, 此时只需设置Ext.useS ...

  10. css控制大小写

    转换不同元素中的文本: text-transform:uppercase //全大写 text-transform:lowercase //全小写 text-transform:capitalize ...