----------------------------------------
author:hjjdebug
date: Fri Aug 14 17:25:19 CST 2020
----------------------------------------
继承,简单的说就是你的就是我的.
但到底是什么概念呢?
1. 子类继承父类,是不是把父类的私有成员变量也继承了, 子类对象的大小是多少呢?
2. 子类调用父类的成员函数,汇编程序是不是调整this指针然后才调用的父类地址?
3. 外部调用子类的成员函数, 该成员函数子类没有但其父类有,具体是怎样实现传递的呢?
带着这些问题,我写了简单的测试代码进行了研究.
直入主题,先从main.cpp 说起
cat main.cpp
#include "C2.h"
int main()
{
C2 obj;
obj.setData(8);
obj.printMe(); //直接翻译为调整this指针指向父类,调用父类地址处函数
/*
=> 0x00005555555548f8 <+53>: lea -0x24(%rbp),%rax //this 指针
0x00005555555548fc <+57>: add $0x4,%rax //调整到父类C1a类
0x0000555555554900 <+61>: mov %rax,%rdi //调用父类函数地址.
0x0000555555554903 <+64>: callq 0x555555554822
*/
return true;
}
C2类公有继承了C1,C1a类.
$ cat C2.h
#ifndef _C2_H
#define _C2_H
#include "C1.h"
#include "C1a.h"
class C2 : public C1, public C1a
{
public:
C2(){}
~C2(){}
void setData(int data);
int y;
};
#endif
补全C1.h, C1a.h 及其对应的cpp 文件. C1.cpp, C1a.cpp C2.cpp
hjj@hjj-Inspiron:~/temp$ cat C1.h
#ifndef _CLASS_H
#define _CLASS_H
class C1
{
public:
C1(){}
~C1(){}
void setData(int data);
int getData();
int x;
};
#endif
hjj@hjj-Inspiron:~/temp$ cat C1a.h
#ifndef _C1A_H
#define _C1A_H
class C1a
{
public:
C1a(){}
~C1a(){}
void printMe();
void setData(int data);
int getData();
int xa;
};
#endif
hjj@hjj-Inspiron:~/temp$ cat C1.cpp
#include
#include "C1.h"
void C1::setData(int data)
{
x = data;
}
int C1::getData()
{
return x;
}
hjj@hjj-Inspiron:~/temp$ cat C1a.cpp
#include
#include "C1a.h"
void C1a::printMe()
{
printf("xa:%d\n",xa);
}
void C1a::setData(int data)
{
xa = data;
}
int C1a::getData()
{
return xa;
}
hjj@hjj-Inspiron:~/temp$ cat C2.cpp
#include
#include "C2.h"
void C2::setData(int data)
{
printf("c2 SetData()\n");
y=data+1;
C1::setData(data); //C2 的this 指针与C1的重回,不用调整了
/*
0x000055555555489a <+40>: mov -0x8(%rbp),%rax //this 指针
0x000055555555489e <+44>: mov -0xc(%rbp),%edx //参数
0x00005555555548a1 <+47>: mov %edx,%esi //第一参数送esi
0x00005555555548a3 <+49>: mov %rax,%rdi //指针送rdi
0x00005555555548a6 <+52>: callq 0x5555555547fa
*/
C1a::setData(data); //调整this 指针到C1a,然后调用setData(int)
/*
=> 0x00005555555548ab <+57>: mov -0x8(%rbp),%rax //this 指针
0x00005555555548af <+61>: lea 0x4(%rax),%rdx //调整this 指针
0x00005555555548b3 <+65>: mov -0xc(%rbp),%eax //参数
0x00005555555548b6 <+68>: mov %eax,%esi //第一参数送esi
0x00005555555548b8 <+70>: mov %rdx,%rdi //指针送rdi , 调用地址
0x00005555555548bb <+73>: callq 0x55555555484a
*/
}
对于简单的C1,C1a类没什么好说的, 关键是C2类继承了C1,C1A 类, 那它是怎么调用的C1,C1a中的成员函数呢, 注释的汇编代码里
已经给出了答案. 把玩跟踪代码,就可以得出如下结论了. 本帖的核心就是这几行汇编代码.!
结论:
1. 子类继承父类,是不是把父类的私有成员变量也继承了, 子类对象的大小是多少呢?
答:是的. 它是父类的大小加上自己的大小合并为一个大的数据结构.
2. 子类调用父类的成员函数,汇编程序是不是调整this指针然后才调用的父类地址?
答. 是的
3. 外部调用子类的成员函数, 该成员函数子类没有但其父类有,具体是怎样实现传递的呢?
答: 调整this 指针到父类位置,调用父类函数.
所谓继承,就是子类把父类的成员变量全部拿过来,在此基础上补充自己的专有变量,构成一个
更大的数据结构. 当我们在操作不同的变量时,要传递不同父类的this指针.
操作不同的变量,就是调用不同的成员函数包括父类的成员函数.
这就是继承的含义.
当然,继承通常都是public属性,函数与变量根据安全的需要还细分为public,protect,private 属性.