更多知识点请点击:C++知识点目录索引
1. 类和对象
类:和结构体类似,存在数据(变量),还有方法(函数),即类包含成员变量和成员函数
对象:类的实例,将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。
2. 类和对象的特点
类:具有封装性,将变量和函数封装到类当中,类的访问限定符(public、private、protected)体现了面向对象的封装性
对象:封装,继承,多态
3. 具体例子
3.1 类的定义
//类内定义成员函数
class Person
{
public:
void Show()//可以直接从类外部访问,作用域为:到下一个public,或者类结束
{
cout<<_name<<endl;
cout<<_sex<<endl;
cout<<_age<<endl;
}
private://不可直接从类外部访问
char* _name;
char* _sex;
int _age;
}
//类外定义成员函数
class Person
{
public:
void Show();//可以直接从类外部访问,作用域为:到下一个public,或者类结束
private://不可直接从类外部访问
char* _name;
char* _sex;
int _age;
}
void Date::Show()//类外写成员函数必须指明函数属于哪一个类域
{
cout<<_name<<endl;
cout<<_sex<<endl;
cout<<_age<<endl;
}
3.2 实例化:
class Person
{
public:
void Show()
{
cout<<_name<<endl;
cout<<_sex<<endl;
cout<<_age<<endl;
}
private:
char* _name;
char* _sex;
int _age;
}
void Test()
{
Person P;//类的对象
p._name = "张三";
P._sex = "男";
P._age = 10;
}
4. 类的作用域:
成员函数和成员变量都在类的作用域内,类内部成员可直接访问
类外定义成员,使用::表示在哪个作用域
例:
//类的声明
class Person
{
Public:
void show();
private:
char* _name;
int _age;
}
//定义
Person::show()
{
cout<<_name<<endl;
cout<<_age<<endl;
}
5. 类的大小:
和结构体内存对齐规则一致
只取决于成员变量的大小,成员函数不占对象空间(原因:将成员函数放在公共代码区,供大家使用)
空类的大小为1,开辟一个空间表示类的存在
内存对齐规则
- 第一个成员在与结构体变量偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8
Linux中的默认值为4- 结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
6. 内存对齐的原因
由于存在内存访问机制,每次访问内存时从0号地址处连续读取4字节(或4字节的整数倍);
如果不存在内存对齐,读取一个变量时会读取两次或者三次甚至更多,反而降低效率
内存对齐的前提下,读取一次即可提高效率
7. this指针
每个成员函数都有一个指针形参,它的名字是固定的,称为this指针,this指针是隐式的。(构造函数比较特殊,没有这个隐含this形参)
编译器会对成员函数进行处理,在对象调用成员函数时,对象地址作实参传递给成员函数的第一个形参this指针。
this指针是成员函数隐含指针形参,是编译器自己处理的,我们不能在成员函数的形参中添加this指针的参数定义,也不能在调用时
显示传递对象的地址给this指针。
类的
void show();//原本成员函数
void show(Date* this);//编译器处理的成员函数
8. 默认成员函数
8.1 构造函数
没有返回值,可以有参数,没有参数的构造函数被认为是缺省构造函数,但缺省构造函数只允许有一个
与类同名,可以有多个构造函数 ,可以重载, 没有隐含的this形参
作用是将对象初始化,创造出对象时系统自动调用构造函数进行对象的实例化
例:
class Date
{
public:
//两个缺省参数只可取其一
Date();//(1)类内声明
/*Date(int year=1900,int month=1,int day=1)//(2)类内定义
{
_year=year;
_month=month;
_day=day;
}*/
void show()
{
cout<<_year<<endl;
cout<<_month<<endl;
cout<<_day<<endl;
}
private:
int _month;
int _year;
int _day;
}
//类外定义:
Date::Date()
{
_year=1900;
_month=1;
_day=1;
}
注意:如果没有定义构造函数,编译器会自己生成默认缺省构造函数(无参的构造函数),如果是成员变量是内置类型,默认构造函数不会初始化,如果成员变量是自定义类型,自动生成的默认构造函数调用自定义类型的构造函数进行初始化
例:
//自定义类型
class Time
{
public:
Time()//自定义类型的构造函数
{
cout<<_hour<<endl;
}
private:
int _hour;
}
class Date
{
public://无构造函数,生成默认的缺省构造函数(无参的构造函数),什么也不做(成员函数有自定义类型除外)
void show()
{
cout<<_year<<endl;
cout<<_month<<endl;
cout<<_day<<endl;
}
private:
int _month;
int _year;
int _day;//默认生成的构造函数不会对齐初始化
Time _t;//调用自定义类型的构造函数对其进行初始化
}
8. 2 析构函数
与类同名,并且与构造函数工作性质相反,故有~ 标识析构函数
当对象生命周期结束(即出了类的作用域),系统自动调用析构函数
不支持重载,完成清理工作(动态开辟),保证对象的初始化和销毁
例:
class SeqList
{
public:
SeqList(size_t capacity=0)//构造函数
{
if(capacity > 0)
{
_a=(int*)malloc(sizeof(int)*capacity);
_capacity=capacity;
_size=0;
}
else
{
_a=NULL;
_capacity=_size=0
}
}
~SeqList()//析构函数
{
free(_a);
_size=_capacity=0;
}
private:
int* _a;
size_t _size;
size_t _capacity;
}
8.3 拷贝构造函数
参数是一个同类型的对象,使用同类对象进行初始化
拷贝构造函数使用引用
如果没有定义拷贝构造函数,系统自动生成缺省拷贝构造函数并进行初始化
例:
class Date
{
public:
Date(int year=1900,int month=1,int day=1)//缺省参数
{
_year=year;
_month=month;
_day=day;
}
Date(const Date& d)//加引用,防止无限递归
{
_year=d._year;
_month=d._month;
_day=d._day;
}
void show()
{
cout<<_year<<endl;
cout<<_month<<endl;
cout<<_day<<endl;
}
private:
int _month;
int _year;
int _day;
}
8.4 运算符重载
作用:增强代码的可读性
特征:operator + 运算符(例:operator<)
不能重载的运算符: .* :: sizeof ?: :
两种形态:成员函数(一个参数,还有一个隐含的this),全局
例:
class Date
{
public:
Date(int year=1900,int month=1,int day=1);//缺省参数
Date(const Date& d);//加引用,防止无限递归
void show();
bool operator==(const Date& d1,const Date& d2);//类内声明
private:
int _month;
int _year;
int _day;
}
//全局
bool Date::operator==(const Date& d1,const Date& d2)
{
return d1._year==d2._year
&& d1._month==d2.month
&& d1._day==d2._day;
}
//成员函数
class Date
{
public:
Date(int year=1900,int month=1,int day=1);//缺省参数
Date(const Date& d);//加引用,防止无限递归
void show();
bool operator==(const Date& d1,const Date& d2);//成员函数
{
return d1._year==d2._year
&& d1._month==d2.month
&& d1._day==d2.day;
}
private:
int _month;
int _year;
int _day;
}