this指针
- this指针的类型是是类类型* const,比如class B,this指针的类型就是B* const
- this指针的作用域仅限于类内部 * this指针并不是对象的一部分,sizeof的时候不会算上this指针的大小
- this指针在非静态成员函数中使用,其他任何函数都不可以
- this指针是非静态类成员函数的第一个默认参数,且自动隐蔽,编译器自动维护传递,类编写者不能显示传递
- 静态成员函数不会隐式地传递一个this指针,且在静态成员函数中不能访问非静态的成员变量,只可以访问同样静态的成员变量,而非静态成员函数既可以访问静态成员变量,也可以访问非静态成员变量。
- this指针是可以为空的,this指针为空之后,就不可以通过this访问非静态成员变量了,即假设a是A类的成员变量,this为空之后,this->a这样的操作就不可能的,就是访问空指针
- 既然this指针可以为空,那么this为什么是指针,而不是引用就可以知道了。指针可以为空,即有空指针,但是不存在空引用的概念。(但实际上是,在this指针概念提出来的时候,还没有引用的概念)
class CNullPointCall
{
public:
static void Test1();//静态的成员函数Test1
void Test2();
void Test3(int iTest);
void Test4();
private:
static int m_iStatic;?//静态的成员变量,需要在类外初始化
int m_iTest;//非静态的成员变量
};
int CNullPointCall::m_iStatic = 0;//类外初始化静态的成员变量
void CNullPointCall::Test1()
{
cout << m_iStatic << endl;//打印一个静态的成员变量的值
}
void CNullPointCall::Test2()
{
cout << "Very Cool!" << endl;//只是打印一句very cool
}
void CNullPointCall::Test3(int iTest)
{
cout << iTest << endl;//打印传给该函数的参数
}
void CNullPointCall::Test4()
{
cout << m_iTest << endl;//打印一个非静态成员变量的值,相当于this->m_iTest
}
int main()
{
//以下四个调用只有Test4()用到了this指针,1、2、3都是可以正确执行的
CNullPointCall *pNull = NULL; //没错,就是给指针赋值为空,相当于this为空了
pNull->Test1(); // 相当于CNullPointCall::Test1(),访问静态成员函数
pNull->Test2(); // 直接输出一句话
pNull->Test3(13); // 输出传进去的参数
pNull->Test4(); // 输出非静态的成员变量,this->m_iTest,this指针为空,会出错
return 0;
}
_thiscall调用约定
它不是关键字,它是C++类成员函数缺省的调用约定,通过这种约定,让this指针成为成员函数的第一个参数
- _thiscall只能用在类的成员函数上
- 类成员函数的参数从右向左被压入栈
- 如果参数个数确定,this指针通过ecx传递给被调用者;如果参数不确定,this指针在所有参数被压栈后压入堆栈
- 对参数个数不定的,调用者清理堆栈,否则函数自己清理堆栈
来一段代码感受一下
class A
{
public:
int funcontion1(int a, int b);
int funcontion2(int a,...);//在参数列表后面加三个'.'表示可以有不定的参数
};
int A::funcontion1(int a, int b)
{
return a + b;
}
int A::funcontion2(int a, ...)//a表示传的参数的个数
{
va_list ap;//用于获取不确定的参数个数
va_start(ap, a);//获取第一个可选参数地址
int i;
int result = 0;
for (int i = 0; i < a; ++i)
{
result += va_arg(ap, int);//获取下一个参数地址
}
return result;
}
int main()
{
A a;
a.funcontion1(1, 2);
a.funcontion2(3, 1, 2, 3);
return 0;
}
a.funcontion1(1, 2);
00BA18B8 push 2
00BA18BA push 1 //这两部表示参数是从右向左被压入栈的
00BA18BC lea ecx,[a]//这里引入了this指针
00BA18BF call A::funcontion1 (0BA13FCh) //注意,这里this没有被压入栈中
a.funcontion2(3, 1, 2, 3);
00BA18C4 push 3
00BA18C6 push 2
00BA18C8 push 1
00BA18CA push 3
00BA18CC lea eax,[a] //这里引入this指针
00BA18CF push eax //这一步,this指针被压入了栈中
00BA18D0 call A::funcontion2 (0BA1401h)
00BA18D5 add esp,14h
关于this指针的相关问题
- 何时创建:在成员函数的开始执行前构造的,在成员函数的执行结束后清除
- 存放于何处:this指针会因编译器的不同,而放置的位置不同,可能是栈,也可能是寄存器,甚至是全局变量
- 如何访问类中的变量的:this想当于类的指针,如果是结构,那this就是结构的指针了
- 知道一个对象this指针的位置能否直接使用:this指针只有在类成员函数内部才有定义,因此获得一个对象后,也不能通过对象使用this指针,因此也无法知道this指针的位置(只有在成员函数里才有this指针的位置,且在成员函数执行结束后就清除了)。
- 每个类编译后,是否创建一个类中函数表来保存函数指针,以便来调用函数:
普通的类函数都不会创建一个函数表来保存函数指针,只有虚函数才会被放到函数表中。
但即便是虚函数,如果编译器知道调用的是哪个函数,都会直接去调用该函数,而不会通过函数表中的指针间接调用 - this指针如何传递给类中的参数的:大多数编译器通过exc寄存器传递this指针,在调用函数之前,编译器会把对应的对象的地址放到exc寄存器中,而this指针就是指向这个地址
- 为什么this指针不能再静态函数中使用:静态成员函数并不是针对某个类的实例对象,而是属于整个类的,为所有的对象实例所共有。它在作用域的范围内是全局的,独立于对象之外,并且只对类内部的静态成员变量做操作。在实例化一个类的对象的时候,里面不存在静态成员。this是类的实例的指针,因此不能用来操作实例之外的静态成员函数