文章目录
- class定义类
- 声明和定义不分离
- 成员函数声明与定义的分离
- 类的访问限定符
- 类的实例化
- 类对象的大小
- this指针
引入:什么是类呢?
在C语言阶段,结构体成员只能是它的属性,这个结构体就相当于张三,小时候它只被赋予了名字,性别,家庭住址等属性,但是他没有去做某件事的能力,而C++中呢就相当于他长大了,就可以有骑车,跑步,和别人聊天的能力,这种既可以包含属性,又可以有某些行为的,我们就称它为类。
在C++中我们选择用关键字class来代替struct,当然struct也是可以继续用的
class定义类
类的定义有两种方式,一种是定义和声明都放在类体中,另一种是声明和定义分离分别放在.h和.cpp中
声明和定义不分离
成员函数声明与定义的分离
我们把结构体,类等放在头文件.h其中之一的目的就是为了方便我们去看,这个类的功能,那么当成员函数的声明与定义都放在头文件.h中时,未免就会造成头文件代码过多,不容易查看。此时我们就要让声明与定义分离,把成员函数的定义放到.cpp文件中,但是要加上类域,不然编译器就会分不清这个函数到底是普通函数还是成员函数。
例如上述代码成员函数定义在.cpp文件中就要这样写:
要指明类域且返回类型放在最前面。
如果成员函数是内联函数,那么它的声明与定义就不能分离,所以它的定义要定义在头文件中和声明放在一起。
成员函数直接定义在类里,默认相当于加上了inline,编译器就可能会把它当做内联函数处理。加不加inline只是为了提醒编译器,到底是不是内联函数取决于编译器自己。
类的访问限定符
为了安全起见,类引入了三种访问限定符分别为public(公有),private(私密),protected(受保护的)
#include <iostream>
using namespace std;
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
//在类的内部是可以对私密变量进行访问的,
//在外部不能对私密变量访问
int _year;
int _month;
int _day;
};
int main()
{
Date d1, d2;
//d1._year;成员变量_year是私密的不能在外部进行访问,只能在类中进行访问
d1.Init(2004, 1, 01);
d2.Init(2003, 1, 10);
d1.Print();
d2.Print();
return 0;
}
public修饰的成员在类外可以被直接访问
protected和private修饰的成员在类外不能被直接访问
访问限定符的作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止,如果后面没有访问限定符,作用域就到 } 为止,即类结束。
class的默认访问权限为private,struct的默认访问权限为public(因为C++要兼容C)
类的实例化
#include <iostream>
using namespace std;
//类的实例化
class Person
{
public:
void MyName()
{
cout << _name << endl;
}
public:
char* _name;//类的成员变量要加上符号与普通变量加以区分
char* _sex;
int _age;
};
int main()
{
//Person.age = 20;未实例化不能使用类
Person man;
man.MyName();
return 0;
}
其实就和之前的结构体一样你不能直接通过结构体类型去引用结构体的成员。
我们可以通过一个形象的例子来说明,这个类就像是一个房子的图纸,直接引用类的成员就相当于你要去这个图纸里主一样,你要先根据这个图纸把房子盖起来,然后才能去里面住。
这个图纸在还没有去建造的时候这个房子是不占空间的,你只有把房子盖起来了才会占据空间,同时你也可以根据这个图纸建造出很多个这样的房子,只不过这个房子所在的位置不同,类与建房子一样,可以实例出很多个类变量,且物理存储位置不同,在还没有对类进行实例化时,是不占空间的。
类对象的大小
类的大小是类中属性的大小还是方法的大小,还是属性和方法大小的总和呢?
先说结论类的大小只包括类中属性的大小,属性就是成员变量,不是方法。
我们还是拿房子举例,类中的成员变量就相当于是这个房子中的厨房,卧室,厕所等,这些属性当然每一个房子都会有,而成员方法就类似于篮球场,足球场等,可不可以放在家里呢?当然可以,但是未免也太占空间了,所以一般情况下小区的篮球场,足球场等是所有的居民共用的,所以这里的方法也是如此,它不存储在类中,而是放在一个公共区域内,供所有人使用。
类中成员变量的存储空间符合内存对齐。但是注意当这个类为空类时,就是没有成员变量的情况,默认占的内存空间为1,就相当于这个房子没有厨房,客厅,卧室等,但它仍然是一个房子是要占据空间的,是要让系统知道我这个房子是存在的。
此外结构体为什么要进行内存对齐?
假设你的系统在读取内存时一次读取八个字节,而一个值的存储恰好有一部分是存储在你所读的这八个字节中而另一部分是存储在下一次读取的八个字节中,那么对于这个数你就要读取两次,而如果是内存对齐呢这个数你只需要读一次就可以得到,具体内存对齐规则详见C语言三万字总结这篇文章。
那么又来了你也用我也用他也用这个健身房,怎么知道到底是谁再用呢?所以这就引出了另一个问题就是this指针。
this指针就像是在健身房人脸识别一样,每一个人都有一个脸,系统可以通过这张脸来识别你的身份。这张脸不需要你去设定,系统会自动帮你加上并识别。
#include <iostream>
using namespace std;
//this指针
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1, d2;
d1.Init(2004, 1, 01);
d2.Init(2003, 1, 10);
d1.Print();
d2.Print();
return 0;
}
上述初始化函数Init()是调用的同一个函数,是怎么确定这个此时是给哪个类对象进行初始化的呢?你可能会说这不是写了d1.,d2.了吗,肯定是对它的成员进行初始化呀,我们要追根溯源找到它的本质原因,其实函数调用的括号里有一个默认的this指针。
C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
this指针
this指针是你调用类成员方法时自动添加上的。
你不能主动地去给这个方法加上形参this,或指定这个对象的地址。
**this指针是存放在栈帧里面的,本质和形参一样没有区别,**只不过是隐式传过去的。
this指针不是存放在对象里面的是存放于栈中的