C++函数编译原理和成员函数的实现

对象的内存中只保留了成员变量,除此之外没有任何其他信息,程序运行时不知道 stu 的类型为 Student,也不知道它还有四个成员函数 setname()、setage()、setscore()、show(),C++ 究竟是如何通过对象调用成员函数的呢?

C++函数的编译


C++和C语言的编译方式不同。C语言中的函数在编译时名字不变,或者只是简单的加一个下划线_(不同的编译器有不同的实现),例如,func() 编译后为 func() 或 _func()。

而C++中的函数在编译时会根据它所在的命名空间、它所属的类、以及它的参数列表(也叫参数签名)等信息进行重新命名,形成一个新的函数名。这个新的函数名只有编译器知道,对用户是不可见的。对函数重命名的过程叫做名字编码(Name Mangling),是通过一种特殊的算法来实现的。

Name Mangling 的算法是可逆的,既可以通过现有函数名计算出新函数名,也可以通过新函数名逆向推演出原有函数名。Name Mangling 可以确保新函数名的唯一性,只要函数所在的命名空间、所属的类、包含的参数列表等有一个不同,最后产生的新函数名也不同。

如果你希望看到经 Name Mangling 产生的新函数名,可以只声明而不定义函数,这样调用函数时就会产生链接错误,从报错信息中就可以看到新函数名。请看下面的代码:

#include <iostream>
using namespace std;

void display();
void display(int);
namespace ns {
	void display();
}
class Demo {
public:
	void display();
};
int main() {
	display();
	display(1);
	ns::display();
	Demo obj;
	obj.display();
	return 0;
}

该例中声明了四个同名函数,包括两个具有重载关系的全局函数,一个位于命名空间 ns 下的函数,以及一个属于类 Demo 的函数。它们都是只声明而未定义的函数。

在 VS 下编译源代码可以看到类似下面的错误信息:

小括号中就是经 Name Mangling 产生的新函数名,它们都以?开始,以区别C语言中的_。

__cdecl,__thiscall是函数调用约定,也就是告诉编译器用于建栈,参数压栈以及获得返回值的规则。

有兴趣的请看:https://blog.csdn.net/qq826364410/article/details/88902296

成员变量、成员函数的存储

成员变量:C++会将class中的成员变量提取出来放在栈区的一个同名的struct里面,与struct有相同的内存布局和字节对齐方式。

关于内存对齐,有兴趣的可以点这里:https://blog.csdn.net/qq826364410/article/details/88421502

成员函数:将成员函数提取出来放在代码区,编译成员函数时要额外添加一个参数,把当前对象的指针传递进去,通过指针来访问成员变量。

静态成员函数:将静态成员函数放在全局静态区。

下图是C++内部编译实现:

成员函数的调用


从上图可以看出,成员函数最终被编译成与对象无关的全局函数。

如果成员函数中使用到了成员变量该怎么办呢?成员变量的作用域不是全局,不经任何处理就无法在函数内部访问。

C++规定,编译成员函数时要额外添加一个参数,把当前对象的指针传递进去,通过指针来访问成员变量。

假设 Demo 类有两个 int 型的成员变量,分别是 a 和 b,并且在成员函数 display() 中使用到了,如下所示:

void Demo::display() {
	cout << a << endl;
	cout << b << endl;
}

那么编译后的代码类似于:

void new_function_name(Demo * const p) {
	//通过指针p来访问a、b
	cout << p->a << endl;
	cout << p->b << endl;
}

使用obj.display()调用函数时,也会被编译成类似下面的形式:

// obj.display()
new_function_name(&obj);

这样通过传递对象指针就完成了成员函数和成员变量的关联。这与我们从表明上看到的刚好相反,通过对象调用成员函数时,不是通过对象找函数,而是通过函数找对象。

总结:

编译器通过指针来访问成员变量,指针指向哪个对象就使用哪个对象的数据;编译器通过指针的类型来访问成员函数,指针属于哪个类的类型就使用哪个类的函数。

 

最后需要提醒的是,Demo * const p中的 const 表示指针不能被修改,p 只能指向当前对象,不能指向其他对象。

关于C++中更多const的用法,请看:https://blog.csdn.net/qq826364410/article/details/88674252

  • 10
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值