一、类的定义
1、类定义的格式
类的关键字是class,后面接上我们自己取的一个名称,然后接上{};{}里面是类的主体,花括号后面必须要有分号 ;
类的主体里面为类的成员;类里面的变量称为类的属性或者成员变量,类里面的函数称为方法或者成员函数;
###代码示例:
#include<iostream>
using namespace std;
//定义一个日期的类
class Date//Data是类的名称
{
//属性(成员变量)
int _day;
int _month;
int _year;
//方法(成员函数)
void Init(int day, int month, int year)
{
_day = day;
_month = month;
_year = year;
}
};
C++中的类和C中的结构体定义方式差不多;
在C++里面,struct升级成了类,class和struct都可以定义类;同时,C++中的struct和C中的struct有不同的地方:
(1)C++中的struct中可以定义函数,C中不行;
(2)C++中用struct声明的类名可以直接去定义一个实体;
class或者struct定义好类之后,可以直接使用这个类名去定义一个对象,在这里的体现就是直接用Date 去定义一个实体(也就相当于C中用struct Date去定义一个实体),但是在C中却不能直接用Date去定义一个实体;
###代码示例:
1、struct 也可以定义类;
//定义一个日期的类
struct Date//Data是类的名称
{
//属性(成员变量)
int _day;
int _month;
int _year;
//方法(成员函数)
void Init(int day, int month, int year)
{
_day = day;
_month = month;
_year = year;
}
};
2、直接用类名就可以定义一个实体;
注意:在C++中同时兼容了C中用struct Date去定义一个实体的写法;
2、访问限定符
在C++的类中引入了访问限定符的概念,这是一种实现封装的方式;这里简单介绍;
分别是公有、私有、保护;
用代码来引入这个概念:
class Date//Data是类的名称
{
private:
//属性(成员变量)
int _day;
int _month;
int _year;
public:
//方法(成员函数)
void Init(int day, int month, int year)
{
_day = day;
_month = month;
_year = year;
}
};
每一个限定符都在类里面,这个限定符的限定的范围是从这个限定符开始到下一个限定符结束或者到 } 结束;
用public限定的内容外部可以访问;用private和protected限定的外部不能访问;这里提到的private和protected是一样的,后面才会区分;
若是在class类里面不用访问限定符,那么默认为私有;若是在struct类里面不用访问限定符,默认为公有;
一个类里面可以有多个相同的访问限定符,但是这样和写在一起是一样的效果,
3、类域
类也是一个域,类的所有成员都在类的作用域中,当类的成员不在类中定义时,需要用类名加上 :: (域作用限定符)来找到类中的成员,再去定义;
比如类中的函数不在类中定义只在类中声明:
若是直接这样写会报错,这是因为找不到成员变量(_day、_month、_year)
应该这样写:
void Date::Init(int day, int month, int year)
{
_day = day;
_month = month;
_year = year;
}
此时定义的就是类中的成员函数。
另外:在类中定义的函数都是内联函数,若是定义在类外面就不是内联函数了。
二、实例化
1、实例化的概念
类得到实例化就是上文说到的用类名去定义一个实体,这个实体就是对象;类中的成员变量都只是声明,并没有开空间,不能直接使用,必须实例化一个对象,才能使用;这里和C中结构体的概念相同,结构体也要先定义一个结构体类型的实体才能使用结构体中的成员变量;
###代码示例:
class Date//Data是类的名称
{
private:
//属性(成员变量)
int _day;
int _month;
int _year;
public:
//方法(成员函数)
void Init(int day, int month, int year)
{
_day = day;
_month = month;
_year = year;
}
void Print()
{
cout << _year << '/' << _month << '/' << _day << endl;
}
};
int main()
{
Date d1;
Date d2;
d1.Init(1, 1, 2020);
d1.Print();
d2.Init(1, 2, 2023);
d2.Print();
return 0;
}
只能访问公有的。
2、对象的大小
对象的大小就是用类实例化的对象的大小;对象包含独立的数据空间;对象的大小一般是对象中成员变量也就是属性的大小,这里计算大小和C中结构体计算大小一样,需要用到内存对齐;成员函数一般不会影响对象的大小,为什么呢?首先函数被编译之后是一段指令,对象中没法存储,这段指令存储在一个单独的区域(代码区),若是非要存储也只是存储函数的指针;再者,其实也没有必要在对象中存储成员函数,一个类的实例化出的许多个对象的区别只是属性不一样,但是要调用的函数都是一样的,若是每次都算成员函数的大小就会有浪费;
内存对其规则:
(1)第一个成员变量对齐到偏移量为0的地方;
(2)其他的成员变量对齐到自己对齐数的整数倍处(对齐数是编译器默认的对齐参数和这个成员变量大小的较小值)(VS中默认的对齐数是8);
(3)最终的类的大小是所有成员变量中最大对齐数的整数倍;
(4)若是嵌套定义结构体那么嵌套在里面的每一个结构体都要对齐到自己的成员变量中最大对齐数的整数被处,最终整个结构体的大小是所有结构体(外层和嵌套)最大对齐数的整数倍。
###代码示例:
class A
{
char x;
int y;
void Print()
{
cout << x << ' ' << y << endl;
}
};
class B
{
char x;
int y;
};
class C
{
void Print()
{
cout << 1 << endl;
}
};
int main()
{
A a;
B b;
C c;
cout << sizeof(a) << endl;
cout << sizeof(b) << endl;
cout << sizeof(c) << endl;
cout << sizeof(A) << endl;
return 0;
}
c的大小是1,这里不是说里面的函数有大小,这里的1只是起占位标识对象存在而存在的;
三、this指针
上文说到相同的类实例化出不同的对象的里面的函数其实都是用的同一份,那么对于不同的对象调用时如何知道是哪个对象在调用呢?这里引入this指针的概念;
this指针是隐含的,实际上并不显示出来;
比如上文中日期的类,里面初始化的函数的原型是:
void Init(Date* const this,int day,int month,int year);
调用时的实际传参是这样的:
d1.Init(&d1 , 1 , 1 , 2020);
值得注意的是:在函数的实参和形参处不能出现this指针传参的形式(编译时会自动处理),但是在函数定义时可以用this指针来定义函数里面的内容;
this指针的作用就是标识调用类里面的函数时是针对于哪一个对象的。
###代码示例:
class Date
{
public:
void Init(int day, int month, int year)
//不能写Init(Date* const this ,int day,int month,int year)
{
this->_day = day;
_month = month;
this->_year = year;
}
private:
int _day;
int _month;
int _year;
};
int main()
{
Date d1;
d1.Init(1, 1, 2020);
//不能写d1.(&d1,1,1,2020);
}