C++语言学习(十四)——C++类成员函数调用分析
一、C++成员函数
1、C++成员函数的编译
C++中的函数在编译时会根据命名空间、类、参数签名等信息进行重新命名,形成新的函数名。函数重命名的过程通过一个特殊的Name Mangling(名字编码)算法来实现。Name Mangling算法是一种可逆的算法,既可以通过现有函数名计算出新函数名,也可以通过新函数名逆向推导出原有函数名。
Name Mangling算法可以确保新函数名的唯一性,只要命名空间、所属的类、参数签名等有一个不同,那么产生的新函数名也不同。
不同的编译器有不同的 Name Mangling 算法,产生的函数名也不一样。
2、this指针
this指针属性如下:
A、名称属性:标识符this表示。
B、类型属性:classname const
C、值属性:表示当前调用该函数对象的首地址。
D、作用域:this指针是编译器默认传给类中非静态函数的隐含形参,其作用域在非静态成员函数的函数体内。
E、链接属性:在类作用域中,不同类的非静态成员函数中,this指针变量的链接属性是内部的,但其所指对象是外部的,即this变量是不同的实体,但指向对象是同一个。
F、存储类型:this指针是由编译器生成,当类的非静态成员函数的参数个数一定时,this指针存储在ECX寄存器中;若该函数参数个数未定(可变参数函数),则存放在栈中。
this指针并不是对象的一部分,this指针所占的内存大小是不会反映在sizeof操作符上的。this指针的类型取决于使用this指针的成员函数类型以及对象类型。
类的成员函数默认第一个参数为T const register this。
this在成员函数的开始执行前构造,在成员函数执行结束后清除。
二、C++成员函数指针
1、C++成员函数指针简介
C++语言规定,成员函数指针具有contravariance特性,即基类的成员函数指针可以赋值给派生类的成员函数指针,C++语言提供了默认的转换方式,但反过来不行。
C++编译器在代码编译阶段会对类对象调用的成员函数进行静态绑定(虚函数进行动态绑定),类成员函数的地址在代码编译时就确定,类成员函数地址可以使用成员函数指针进行保存。
成员函数指针定义语法如下:
ReturnType (ClassName::* pointerName) (ArgumentLList);
ReturnType:成员函数返回类型
ClassName: 成员函数所属类的名称
Argument_List: 成员函数参数列表
pointerName:指针名称
class Test
{
public:
void print()
{
cout << "Test::print" << endl;
}
};
成员函数指针语法极其严格:
A、不能使用括号:例如&(Test::print)不对。
B、 必须有限定符:例如&print不对,即使在类ClassName作用域内也不行。
C、必须使用取地址符号:直接写Test::print不行,必须写:&Test::print。
Test类的成员函数print的函数指针声明如下:void (Test::*pFun)();
初始化如下:pFunc = &Test::print;
Test类的成员函数print的函数指针声明及初始化如下:void (Test::* pFunc)() = &Test::print;
通常,为了简化代码,使用typedef关键字。
typedef void (Test::*pFunc)();
pFunc p = &Test::print;
可以通过函数指针调用成员函数,示例代码如下:
#include <iostream>
using namespace std;
class Test
{
public:
void print()
{
cout << "Test::print" << endl;
}
};
int main(int argc, char *argv[])
{
void (Test::* pFunc)() = &Test::print;
Test test;
//通过对象调用成员函数
(test.*pFunc)();//Test::print
Test* pTest = &test;
//通过指针调用成员函数
(pTest->*pFunc)();//Test::print
//pFunc();//error
//error: must use '.*' or '->*' to call pointer-to-member
//function in 'pFunc (...)', e.g. '(... ->* pFunc) (...)'
return 0;
}
上述代码中,.*pFunc
将pFunc绑定到对象test,->*pFunc
绑定pFunc到pTest指针所指向的对象。
成员函数指针不是常规指针(保存的是某个确切地址),成员函数指针保存的是成员函数在类布局中的相对地址。
2、C++成员函数地址
C++成员函数使用thiscall函数调用约定。C++静态成员函数、普通成员函数的函数地址在代码区,虚成员函数地址是一个相对地址。
#include <iostream>
using namespace std;
class Parent
{
public:
Parent(int i, int j)
{
m_i = i;
m_j = j;
cout << "Parent(int i, int j): " << this << endl;
}
virtual void print()
{
cout << "Parent::" << __func__<< endl;
cout << "m_i = "<< m_i << endl;
cout << "m_j = "<< m_j << endl;
}
virtual void sayHello()
{
cout << "Parent::sayHello()" << endl;
}
virtual void func()
{
cout << "Parent::func()" << endl;
}
virtual ~Parent()
{
cout << "~Parent(): " << this << endl;
}
static void display()
{
cout << "Parent::display()" << endl;
}
int add(int v)
{
return m_i + m_j + v;
}
protected:
int m_i;
int m_j;
};
int main(int argc, char *argv[])
{
cout <<&Parent::dis