目录
一:类的引入
1.c++中的struct
- 在C语言中,我们经常使用struct定义结构体,在C++我们也可以利用struct定义结构体,但二者有所不同
- 在C语言中,我们只能在结构体中定义变量,但在C++中,我们不仅可以定义变量,还能定义函数
struct Date
{
void print()
{
printf("%04d-%02d-%02d\n", _year, _month, _day);
}
int _year;
int _month;
int _day;
};
2.class关键字与类
- 在C++中,我们常用class关键字替代struct定义结构体,而把这种能够定义变量和函数的新型结构体,我们称之为类
- 类中的元素称为类的成员:类中的数据称为类的属性或者成员变量; 类中的函数称为类的方法或者成员函数
二:类的定义
- 定义类有两种方式:
- 声明和定义全部放在类体中,注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
class Date
{
public:
void Print()
{
printf("%04d-%02d-%02d\n", _year, _month, _day);
}
private:
int _year;
int _month;
int _day;
};
- 声明放在.h文件中,类的定义放在.cpp文件中,和我们之前编写五子棋和扫雷等游戏一样分离定义
- 在头文件中的部分:
class Date
{
public:
void Print();
private:
int _year;
int _month;
int _day;
};
- 在cpp中的部分:
void Date::Print()
{
printf("%04d-%02d-%02d\n", _year, _month, _day);
}
三:类的访问限定符与作用域
1.访问限定符
- 可以看到,在前面定义类Date时,我使用了public和private这两个关键字
public(公有),private(私有),protectd(保护)
- 这三个关键字为一组,也都是类的访问限定符,给予了类不同变量和函数不同的访问权限
- 功能大致有以下四点:
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- class的默认访问权限为private,struct为public(因为struct要兼容C) 这也是struct和class不同的地方
- private和protectd很好的防止了外部对类中成员的修改,比如上面的Date类,如果我想在类外修改_year,编译器就会报错
2.作用域
- 类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用
::
作用域解析符指明成员属于哪个类域 - 比如上面我们在Date类中定义了Print函数,我们使用时就需要在Print前面加上
Date::
,否则编译器同样会报错
四:类大小计算与实例化
1.实例化
用类类型创建对象的过程,称为类的实例化,比如Date a;
,和int a很相似,不过int是内置类型,Date是我们的自定义类型
- 类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它
- 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量
- 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
- 学过C语言中的struct关键字后不难理解这一点,结构体和类在定义时都是不占用空间的,只有利用类或结构体创建变量后才会占用空间
2.类对象中变量存储的方式
- 类对象中有成员变量和成员函数,那么它们都是存在类对象中的么?
- 我们不妨思考一下,每个类对象的成员变量或许是不同的,但函数都是一致的,要是每个类对象都存储相同的函数,空间消耗是不是大了很多呢?
- 所以我们不妨大胆猜测,类对象中只存储成员变量,而成员函数是存在一块公共的区域
- 可以看到Date类比结构体date多了一个Print函数,但是二者大小一致
- 所以我们可以确定,类对象只存储成员变量,具体如何计算和结构体大小的计算相同
- 忘了如何计算结构体大小的可以看看这篇博客:结构体大小计算
五:this指针
- 可以看到,我们初始化对象d1的时候并没有传递d1的地址,而函数体中没有不同对象的区分,当d1调用InitDate函数时,这个函数怎么知道应该初始化d1还是d2呢?
- C++中通过引入this指针解决该问题,即:C++编译器给每个 “非静态的成员函数“ 增加了一个隐藏的指针参数,让该指针指向函数运行时调用该函数的对象,在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
- 我们可以将InitDate函数看成这样:
void InitDate(Date* this,int year=0,int month=1,int day=1)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
- 不过实际中我们定义时不能定义this指针,这个是编译器自动帮我们传过去的,也是隐藏在成员函数的形参中的,我们不需要写在形参中,调用时也不用手动传递,否则就是越俎代庖
- this指针的特性:
- this指针的类型:
类类型* const
说明this指针我们不能修改) - 只能在 “成员函数” 的内部使用
- this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。(this指针存在函数栈帧或寄存器中)
- this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递