一、继承的相关基本概念

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. UVA 11624 Fire! BFS搜索

    题意:就是问你能不能在火烧到你之前,走出一个矩形区域,如果有,求出最短的时间 分析:两遍BFS,然后比较边界 #include<cstdio> #include<algorithm& ...

  2. 阿里云centos 安装 nodejs npm express

    yum check-update yum install vsftpdvi /etc/vsftpd/vsftpd.conf anonymous_enable=NO service vsftpd sta ...

  3. CentOS安装nvidia显卡驱动

    1.下载 nvidia 相应的驱动: 2.修改/etc/modprobe.d/blacklist.conf文件,在里面加入blacklist nouveau. 3.重建image $ mv /boot ...

  4. leetcode@ [127] Word Ladder (BFS / Graph)

    https://leetcode.com/problems/word-ladder/ Given two words (beginWord and endWord), and a dictionary ...

  5. ffmpeg 的tutorial

    可能是新的: https://github.com/chelyaev/ffmpeg-tutorial https://github.com/chelyaev/ffmpeg-tutorial.git 老 ...

  6. 使用list和tuple

    list Python内置的一种数据类型是列表:list.list是一种有序的集合,可以随时添加和删除其中的元素. 比如,列出班里所有同学的名字,就可以用一个list表示: >>> ...

  7. elecworks 电缆型号管理器

    部件的命名:系列  导线数x尺寸                                            (不含保护类型的电线) 或:系列  导线数G尺寸      G(指保护线颜色gr ...

  8. [OC Foundation框架 - 14] NSNull

    在NSDictionary中,nil代表结束,允许存入 使用NSNull代替   int main(int argc, const char * argv[]) { @autoreleasepool ...

  9. java图片处理

    import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import ja ...

  10. ALV可输入状态下输入金额字段变小数的问题

    http://blog.163.com/mxb_sap@yeah/blog/static/10335262520167109022155/ 小数位数两位    当我在给ALV上给该字段输入整数 '12 ...