深入理解C++中 class的成员变量,和成员函数
下文的第一段代码块中给出了一个普通的类Dog的实现,有私有成员dId,有bark()成员函数描述dog的行为。bark中有使用到成员dId。
在main函数中打印了Dog的大小4byte,可以想见它只存储了成员dId,成员函数并没有包括在类Dog中。然后是bark的普通通访问方式,创建对象,通过.
访问。
之后创建了一个函数指针barkptr,它无返回值,有一个形参Dog*,可以看出barkptr和Dog::bark唯一的区别就是多了个形参Dog*,巧合的是正好bark可以赋值给barkptr,并且我们通过给barkptr传递一个Dog对象tyke的指针还能访问到bark函数,且bark函数还能访问到tyke的私有成员dId。
#include <iostream> //Dog是个普通的类 class Dog{ private: int dId; public: Dog(int id) : dId(id){} void bark(){ std::cout << "I am NO." << dId << ",\tbark! bark!" << std::endl; } }; int main(){ std::cout << "sizeof Dog: " << sizeof(Dog) << std::endl; //普通访问 Dog spike(100); spike.bark(); //获取Dog中成员函数bark的函数指针 void(*barkptr)(Dog*) = ( void(*)(Dog *) )&Dog::bark; //通过this指针访问 Dog tyke(101); barkptr(&tyke); } //执行结果 sizeof Dog: 4 I am NO.100, bark! bark! I am NO.101, bark! bark!
正是因为,C++中对类成员的存储其实类似于C中的结构体,将一组数据成员按序排在一起(这个过程中考虑字节对齐)。而至于对成员函数的存储就类似于C中的普通函数,只是隐式的在成员函数中添加了一个结构体指针,指向数据成员。正数因为这样,上边的访问方式才得以实现。可以看出,C++中的类,其实只是在C的结构体和函数的基础上的少许变更,在加上C++新发明的作用域的概念而实现的。
下文是利用C语言的结构体、全局函数和namespace对C++中类的示意说明。当然从结构体到类远没有这么简单,但我们至少能理清C++类中的成员和成员函数,和C中的什么是相似相对应的。
#include<stdio.h> namespace Dogc { typedef struct { int dId; }Dogc; void bark(Dogc *this_ptr) { printf("I am NO.%d,\tbark! bark!\n", this_ptr->dId); } } int main(){ std::cout << "sizeof Dogc: " << sizeof(Dogc) << std::endl; Dogc tykec; tykec.dId = 12580; bark(&tykec); return 0; }#C++#