时间:2022-10-08 12:55:32 | 栏目:C代码 | 点击:次
在引入类之前,先来回忆一下C语言中的结构体。结构体是一种自定义类型,可以在其中定义变量,如我们所熟悉的日期结构体:
struct Date { int year; int month; int day; };
而在C++中,结构体被升级成了类,结构体中不仅可以定义成员变量,也可以定义成员函数(成员方法):
struct Date { //成员变量 int year; int month; int day; //成员方法 void print() { cout << year << "-" << month << "-" << "day" << endl; } };
在C++中,更喜欢使用class来替代struct,当然它们也有所差别,在之后会说明。
类的定义可以分为两种,即声明和定义全部放在类体中与声明与定义分离。
该方式即为上一举例代码的定义方式。但要注意,如果采用这种方法定义成员函数,编译器可能会将该函数作为内联函数处理。
头文件中成员函数只需要声明:
struct Date { //成员变量 int year; int month; int day; //成员方法 void print(); };
在源文件中对函数进行定义:
void Date::print() { cout << year << "-" << month << "-" << "day" << endl; }
需要注意,print为类域中的函数,如果不加Date::用以指定类域,会导致定义出错。因此,使用该方式定义成员函数时,一定要注意指定类域。
访问限定符分为三种:
(1)public修饰的成员在类外可以直接被访问:
class Date { public: int year; int month; int day; void print() { cout << year << "-" << month << "-" << "day" << endl; } }; int main() { Date date; date.day = 0; }
如上代码,在main函数中可以直接对对象中的成员变量day进行访问。
(2)protected和private修饰的成员变量在类外不能被直接访问
class Date { private: int year; int month; int day; void print() { cout << year << "-" << month << "-" << "day" << endl; } }; int main() { Date date; date.day = 0; }
此时如果在main函数中对直接对象中的成员变量day进行访问,会导致错误
(3)访问权限作用域是从该访问限定符的位置开始直到下一个访问限定符出现时为止
class Date { private: int year; int month; int day; public: void print() { cout << year << "-" << month << "-" << "day" << endl; } };
如上代码,成员变量均为私有的,而成员函数print为公有的。
(4)class的默认访问权限(即不写访问限定符时)为private,struct为public
封装实际上是一种更好的严格管理
将数据和方法封装到类里,可以访问的定义为共有,不想给他人访问的定义为私有或保护。如此一来就做到了隐藏对象的属性和细节,仅仅对外公开接口来和对象进行交互,更加安全高效。
所谓类的实例化,简而言之就是用类类型创建对象的过程。
打个比方,类就好似建筑的图纸,而对象就是根据图纸造出的建筑。对象是真实存在摸得着的,只有实例化出的对象才能够实际存储数据。
学过C语言我们知道如何计算结构体的大小,那么在C++中,类的大小如何确定呢?
我们所不清楚的,就是类中成员函数的大小如何计算。实事上对于同一类的不同对象,处理问题的方法是相同的,如果每个对象都要保存一遍成员方法,未免有些过于浪费空间了。
因此在C++中,成员函数存放在公共代码段。计算类的大小只需要按照C语言中结构体大小的计算规则即可,不需要考虑成员函数。
注意:空类的大小为1byte,不存储有效数据,但需要占位用以表示对象存在。
class Date { private: int _year; int _month; int _day; public: void init(int year, int month, int day) { _year = year; _month = month; _day = day; } }; int main() { Date date1, date2; date1.init(2022, 2, 14); date2.init(2022, 2, 15); }
对于上述代码,有一个问题,date1与date2这两个对象分别都调用了init进行初始化,那么init函数是如何区分该为哪个对象进行初始化的呢?
C++通过引入this指针解决了这个问题。
1、this指针的类型:类类型* const,存放对象的地址
2、只能在成员函数内部使用
3、this指针本质上是成员函数的形参,传参时存放在栈帧中,对象中不存储this指针
4、this指针为隐藏的形参,不需要用户传递
在上述代码实际被处理成了这样:
void init(int year, int month, int day) { this->_year = year; this->_month = month; this->_day = day; }