一、C++类的this指针和友元函数
1.1、this指针
我们来测试一段代码:
#include <iostream>
using namespace std;
class Test
{
public:
void printA(void)
{
cout << "a = " << a << endl;
}
void printB(void)
{
cout << "a = " << a << endl;
}
private:
int a;
int b;
};
class Test1
{
public:
void printA(void)
{
cout << "a = " << a << endl;
}
void printB(void)
{
cout << "a = " << a << endl;
}
void printA1(void)
{
cout << "a = " << a << endl;
}
void printB1(void)
{
cout << "a = " << a << endl;
}
void printA2(void)
{
cout << "a = " << a << endl;
}
void printB2(void)
{
cout << "a = " << a << endl;
}
private:
int a;
int b;
};
int main(void)
{
Test t1;
Test1 t2;
cout << "t1 sizeof : " << sizeof(t1) << endl;
cout << "t2 sizeof : " << sizeof(t2) << endl;
return 0;
}
运行结果:
这段测试代码主要是测试函数方法是否在对象内存储,对于第一个类,只定义了两个函数,第二个类,定义6个函数,所以将类定义的对象大小打印出来。
但是打印出来发现他们两个的大小都一样,而且都是8,刚好是两个int的大小,那么就知道函数其实并不是在对象里面,可是如果她不在里面,每定义的对象又是如何能够输出自己的数据呢?
我们思考一下,在C语言中,我们定义结构体,是怎么将结构体里面的数据输出打印?
#include <stdio.h>
struct test{
int a;
int b;
};
void test_init(struct test *pstruct,int a, int b)
{
pstruct->a = a;
pstruct->b = b;
}
void print_test(struct test *pstruct)
{
printf("a = %d b = %d\r\n", pstruct->a, pstruct->a);
}
int main(void)
{
struct test t1;
test_init(&t1,10,20);
print_test(&t1);
}
通过代码,我们一般都是使用传递指针的方式进行输出,所以起码我们知道在C++中也肯定存在类似地址指针的东西,如果他将对象的地址传递过来,那么我肯定只能访问的是我本身的数据。
这就是C++类中的this指针,他的作用和C语言中的结构体传递的本身指针一样。
如同下面这个例子:
#include <iostream>
using namespace std;
class Test
{
public:
Test(int a, int b)
{
this->a = a;
this->b = b;
}
void print(void)
{
cout << "a = " << this->a << " b = " << this->b << endl;
}
private:
int a;
int b;
};
int main(void)
{
Test t1(10,20);
t1.print();
return 0;
}
在构造函数中,通过this告诉编译器这是我本身的变量,如果没有this,那么就是 **a=a;**那么在构造函数中就没有任何意义。
Test(int a, int b)
{
this->a = a;
this->b = b;
}
如何证明this就是一个指针呢?很简单,如果可以使用*this来操作不就代表他是一个指针了么?
于是我接着去测试一下:
#include <iostream>
using namespace std;
class Test
{
public:
Test(int a, int b)
{
this->a = a;
this->b = b;
}
void print(void)
{
cout << "a = " << this->a << " b = " << this->b << endl;
}
Test & a_add(int a)
{
this->a += a;
return *this;
}
private:
int a;
int b;
};
int main(void)
{
Test t1(10, 20);
t1.print();
t1.a_add(2).a_add(4);
t1.print();
return 0;
}
重点是这个函数:
Test & a_add(int a)
{
this->a += a;
return *this;
}
这个函数实现的功能就是实现a的变化,然后然返回自己本身,这样我们就可以实现多次变化,如下面这种写法:
t1.a_add(2).a_add(4);
首先 t1.a_add(2) 调用,t1的a会加上2,然后返回本身,于是接下来变为t1.a_add(2).a_add(4); -> t1.a_add(4) ,所以最终a = 10+2+4;运行结果如下:
而且通过这个例子,发现this的确是可以通过*this将其本身返回来,所以this应该是一个指针。
既然是指针,那么可以this++么?
答案是不能:
所以我们知道this是 Test * const类型;可是我们看this->a,是可以修改里面的值,所以不可能是 const Test * const,那么有些时候我们也不需要他修改我里面的值,可是this已经隐藏起来没办法在形参里面定义,可以在函数右边加上const,不要再构造函数上面加const,会出现语法错误, 记得这个const是修饰this指针的,不是修饰函数的,函数没有const ,这样this就变成 const Test * const,而加上之后语法也提示不能修改this里面的值了。
1.2、友元函数
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函 数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上 关键字 friend,其格式如下:
friend 类型 函数名(形式参数);
为什么会出现友元这个概念,他一般运用于那个地方,我们来看一段代码:
#include <iostream>
using namespace std;
class Test
{
public:
Test(int a)
{
this->a = a;
}
void print(void)
{
cout << "a = " << this->a << endl;
}
int get_a(void)
{
return a;
}
private:
int a;
};
void my_test(Test &c)
{
cout << "a = " << c.get_a() << endl;
}
int main(void)
{
Test t1(10);
t1.print();
my_test(t1);
return 0;
}
这个函数的目的就是获取对象里面的a的值,然后将其输出,因为a是private变量,所以需要我们提供一个函数来提供a的值,可是如果当 my_test() 这个函数反复调用的时候,将会导致c.get_a() 反复入栈,导致效率降低,可是因为a又是private变量,不能访问,现在如果就只有这个函数能访问,其他的不能访问即可。
所以友元这个概念就出现了,其实说的直白一点,就是我这个函数是你这个类的哥们,我也有权访问你的private变量。
#include <iostream>
using namespace std;
class Test
{
public:
friend void my_test(Test &c);
Test(int a)
{
this->a = a;
}
void print(void)
{
cout << "a = " << this->a << endl;
}
int get_a(void)
{
return a;
}
private:
int a;
};
void my_test(Test &c)
{
cout << "a = " << c.a << endl;
}
int main(void)
{
Test t1(10);
t1.print();
my_test(t1);
return 0;
}
运行结果:
友元的申明可以在类的任何地方。
关于友元使用几点:
1、申明位置
友元声明以关键字 friend 开始,它只能出现在类定义中。因为友元不是授权类的成员,所以它不受其所在类的声明区域public private 和protected 的影响。通常我们 选择把所有友元声明组织在一起并放在类头之后。
2、友元的利弊
友元不是类成员,但是它可以访问类中的私有成员。友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。不过,类的访问权限确实在某些应用场合显得有些呆板,从而容忍了友元这一特别语法现象。
3、注意事项
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。类B是类A 的友元,类A 不一定是类B 的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A 的友元,类C 是B 的友元,类C不一定是类A 的友元,同样要看类中是否有相应的声明。
所建议能不使用就不使用。