一个c++虚函数与this指针的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个c++虚函数与this指针的问题相关的知识,希望对你有一定的参考价值。

father* p=new son;
p->disp(...);
father是父类,son是子类。disp是一个子类重定义过的虚函数。
问题一:p->disp(...);是不是可以写成p->disp(p,...);
问题二:p的类型是不是father*
问题三:子类disp函数的this指针是不是son*类型的
问题四:如果第三的问题回答“是”请回答第四题,回答“不是”的,请回避!
那么如果isp函数的this指针是 son*类型的,用p调用disp的时候,我们将p的值传递给disp的this指针,那么既然p是father*类型的,而this是son*类型的,则上述操作就相当于把父类的指针转换为子类指针,这不是与父类指针不能自动(隐式)转换为子类指针矛盾么?

    不可以。

    是。

    是。

你这个疑问就实际上涉及到了编译技术。this指针你会发现他是C++的关键字,而不是在那个头文件里声明的变量。也就是说,this指针并不是一个真实存在的C++语言变量,“父类指针不能自动(隐式)转换为子类指针”实际上是C++语言的变量类型规则,但this指针并非一个变量,所以不需要遵循此规则。从执行中的程序来说,this指针是帮助函数确定对象的位置。

如果非要问,this指针到底是储存在哪里?你去看百度百科,它是这样说的“不存在所谓的this的“位置”,只是this表示了对象的存储位置而已。&this违反语义规则,是错误的用法,不会编译通过。”当然,这是从C++语言的层面上来谈。在程序运行中,其实确实是有一个地方储存this指针的值的,不过这只有在非静态函数被调用才存在的。在X86处理器中,储存这个值的地方是寄存器ecx,X86-64储存这个值的地方是rcx。下面给出例子。

void G(IA* a)

a->F();

这段对应的汇编语言重点如下:

mov     rcx, [rsp+28h+arg_0] <——这里就是把对象的首地址(就是变量a的值)放在rcx中。

call    qword ptr [rax]              <——调用F()函数。


virtual void F()

    this->member++;

mov     [rsp+arg_0], rcx        <——将rcx(其实就是所谓this指针)压进栈以防rcx寄存器有他用。

mov     rax, [rsp+arg_0]

mov     eax, [rax+0Ch]          <——通过this指针找到成员变量member的位置。

inc     eax                             <——执行自增操作。

看到了吧,this指针不过就是类成员函数被调用时,被临时储存到rcx寄存器的对象首地址。

之所以啰嗦这么多,意思就是让你明白(如果你被上面所述搞得一头雾水),从程序实际运行的角度上看,this指针与其说是C++的指针,还不如说是编译技术里的东西,汇编/机器语言里根本没有类型一说(当然,机器最多分整数运行储存单元和浮点数运算储存单元),自然不存在什么类型转换了。

参考技术A 1.
不可以。
2.
是。
3.
是。
你这个疑问就实际上涉及到了编译技术。this指针你会发现他是C++的关键字,而不是在那个头文件里声明的变量。也就是说,this指针并不是一个真实存在的C++语言变量,“父类指针不能自动(隐式)转换为子类指针”实际上是C++语言的变量类型规则,但this指针并非一个变量,所以不需要遵循此规则。从执行中的程序来说,this指针是帮助函数确定对象的位置。
如果非要问,this指针到底是储存在哪里?你去看百度百科,它是这样说的“不存在所谓的this的“位置”,只是this表示了对象的存储位置而已。&this违反语义规则,是错误的用法,不会编译通过。”当然,这是从C++语言的层面上来谈。在程序运行中,其实确实是有一个地方储存this指针的值的,不过这只有在非静态函数被调用才存在的。在X86处理器中,储存这个值的地方是寄存器ecx,X86-64储存这个值的地方是rcx。下面给出例子。
void G(IA* a)

a->F();
这段对应的汇编语言重点如下:
mov

rcx,
[rsp+28h+arg_0]
<——这里就是把对象的首地址(就是变量a的值)放在rcx中。
call

qword
ptr
[rax]

<——调用F()函数。
virtual void F()

this->member++;
mov

[rsp+arg_0],
rcx

<——将rcx(其实就是所谓this指针)压进栈以防rcx寄存器有他用。
mov

rax,
[rsp+arg_0]
mov

eax,
[rax+0Ch]

<——通过this指针找到成员变量member的位置。
inc

eax

<——执行自增操作。
看到了吧,this指针不过就是类成员函数被调用时,被临时储存到rcx寄存器的对象首地址。
之所以啰嗦这么多,意思就是让你明白(如果你被上面所述搞得一头雾水),从程序实际运行的角度上看,this指针与其说是C++的指针,还不如说是编译技术里的东西,汇编/机器语言里根本没有类型一说(当然,机器最多分整数运行储存单元和浮点数运算储存单元),自然不存在什么类型转换了。
参考技术B 不可以。
是。
是。
你这个疑问就实际上涉及到了编译技术。this指针你会发现他是C++的关键字,而不是在那个头文件里声明的变量。也就是说,this指针并不是一个真实存在的C++语言变量,“父类指针不能自动(隐式)转换为子类指针”实际上是C++语言的变量类型规则,但this指针并非一个变量,所以不需要遵循此规则。从执行中的程序来说,this指针是帮助函数确定对象的位置。
如果非要问,this指针到底是储存在哪里?你去看百度百科,它是这样说的“不存在所谓的this的“位置”,只是this表示了对象的存储位置而已。&this违反语义规则,是错误的用法,不会编译通过。”当然,这是从C++语言的层面上来谈。在程序运行中,其实确实是有一个地方储存this指针的值的,不过这只有在非静态函数被调用才存在的。在X86处理器中,储存这个值的地方是寄存器ecx,X86-64储存这个值的地方是rcx。下面给出例子。
1234void G(IA* a) a->F();
这段对应的汇编语言重点如下:
mov

rcx,
[rsp+28h+arg_0]
<——这里就是把对象的首地址(就是变量a的值)放在rcx中。
call

qword
ptr
[rax]

<——调用F()函数。
1234virtual void F() this->member++;
mov

[rsp+arg_0],
rcx

<——将rcx(其实就是所谓this指针)压进栈以防rcx寄存器有他用。
mov

rax,
[rsp+arg_0]
mov

eax,
[rax+0Ch]

<——通过this指针找到成员变量member的位置。
inc

eax

<——执行自增操作。
看到了吧,this指针不过就是类成员函数被调用时,被临时储存到rcx寄存器的对象首地址。
之所以啰嗦这么多,意思就是让你明白(如果你被上面所述搞得一头雾水),从程序实际运行的角度上看,this指针与其说是C++的指针,还不如说是编译技术里的东西,汇编/机器语言里根本没有类型一说(当然,机器最多分整数运行储存单元和浮点数运算储存单元),自然不存在什么类型转换了。
参考技术C

    如果是虚函数,你可以重载写成p->disp(p,...),但是如果是纯虚函数,必须和父类的虚函数一模一样,将其替换掉,不然你仍然属于一个虚类,不能直接使用。不过我不是很明白p->disp(p,...)是什么意思

    p的类型不是father*是son*,如果son继承了father,父类指针可以自动转换成相应的子类指针

    disp中的this是子类son的

    p不是father,只是son的,所以你第四点有问题,如果你在子类中仍要使用父类的成员,要明确提出来,father::disp(),因为C++中没有java的super指针,那个p是子类的,就是this,所以没有必要在把p传入,写成p->disp(p,...)

追问

father* p=new son;为什么p不是father类型的?还有p->disp(p,...);这句话的意思是显示的把地址传递给this指针。

追答

就是你说的自动隐式转换啊,父类指针,可以自动转换成任何一个子类指针,但子类指针不能自动转换为父类指针

追问

你说反了。。。。。是子类可以自动转换为父类指针,,,,,

追答

...看错了...定义的时候可以的,但是其他时候要显示转换,p的确是一个父类指针

子类包含有父类,把子指针赋给父指针时其实只是把子类中父类部分的地址赋给了父类指针而已,也就是说子类的成员把父类的成员给顶替了。this仍然是父类的

#include <iostream>
using namespace std;
class Father
public:
void a()cout<<"111"<<endl;
virtual void disp()cout<<"123"<<endl;;
;
class son:public Father
public:
void disp()
this->a();
cout<<"456"<<endl;

;
 
int main()
Father * p=new son();
p->disp();
getchar();
return 0;

c++虚函数详解

 

(1)定义一个虚函数,是为了允许用基类的指针调用子类的这个函数。

(2)定义一个纯虚函数,代表函数不被实现,是为了实现一个接口的作用,规范继承这个类的程序员必须实现这个函数。virtual void fun() =0 ;

 

 

虚表

   1. 虚表是一个指针数组,其元素是虚函数的指针,每个元素对应一个函数的函数指针。

  

 

 

 虚表指针

  1. 虚表属于类,而不属于某个具体的对象,因此,同一个类的所有对象都使用同一个虚表。

  2. 每个对象内部,包含一个虚表指针。

  

 

 

 

 

 

 

vlog参考:

  https://blog.csdn.net/isunbin/article/details/88891582

 

以上是关于一个c++虚函数与this指针的问题的主要内容,如果未能解决你的问题,请参考以下文章

虚函数和基类中的this指针的问题!

c++虚函数问题,大神请进

C++多态与this指针问题

C++面向对象高级编程(下) 第二周笔记 GeekBand

C++之中this指针与类的六个默认函数小结

C++中的this指针是啥意思?