C语言面向过程,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题
C++是基于面向对象,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成,C++不是纯面向对象的语言,C++既有面向过程,也有面向对象可以混合编程。C语言面向过程,数据和方法是分离的。CPP面向对象,数据和方法是封装在一起的,如struct里即可用存数据也可以调用方法(函数)
struct ListNodeCPP{
int val;
ListNodeCPP* next;
};
int main(){
//struct ListNodeCPP n1; 就不需要这样调用了
ListNodeCPP n1;
}
所以这里的struct已经不仅仅是结构体,在cpp中已经升级成了类名
类包括成员变量和成员函数
下图为类的访问限定符及封装
Warning:
在class中,如果不写访问限定符默认是私有
在struct中,如果不写访问限定符默认是公有
class类中的private里的成员变量前面都会加个下划线因为在函数复制时更加容易区分
面向对象的三大特性:封装、继承、多态
本节只介绍封装,封装是将数据和操作数据进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互
封装本质上是一种管理,类似兵马俑,如果什么都不管兵马俑就会被随意破坏那么我们首先建一座房子把兵马俑给封装起来。
但是我们不能全部封装起来,所以开放了搜票通道,买了门票的可以进去参观。类也是一样,我们使用类数据和方法都封装一下。
不想给别人看的,我们使用proteced/private把成员封装起来。开放一些共有的成员函数对成员合理的访问。所以封装本质上是一种管理
Warning:
在类中private域声明的变量仅仅是声明,但是没有开空间,我们只有在实例化的时候才算是定义,public域下亦是如此。
总结就是定义是开空间,在实例化后才是定义,class里只是声明
用类类型创建对象的过程,称为类的实例化
那么定义一个空类呢?
class Cpp{}
那么sizeof的大小为1 , 而不是0,因为如果一个类没有成员,那么他的对象需要给1byte进行占位
标识对象存在,这1个byte不存储有效数据
C++编译器给每个非静态成员函数增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中,所以成员变量的操作都是通过该指针去访问
下面的代码为编译器处理成员函数的this指针,也可以不写那么编译器会自动传隐含的this指针
class Date{
public:
void date(int year, int month, int day){
this->_year = year;
this->_month = month;
this->_day = day;
}
void Print(){
cout << _year << "/" << _month << "/" << _day <<endl;
}
private:
int _year;
int _month;
int _day;
};
this指针特性:
上图为默认的成员函数,那么如果定义了一个class而里面什么都不写的话,仍会自动生成上面6个默认成员函数
我们首先要介绍的就是构造函数,因为一般在C语言中一般会先进行初始化,在C++中一般写在类里,这样我们在实例化的过程中就可以省去很多时间,而且避免了忘记初始化的风险。
构造函数特征:
所以构造函数实际上能够做到我们对象一定义出来就初始化了
class Date{
public:
Date(){
_year = 0;
_month = 0;
_day = 0;
}
//带参构造函数
Date(int year, int month, int day){
_year = year;
_month = month;
_day = day;
}
//全缺省,注意默认构造函数只能有一个,所以只能选一种我们推荐用全缺省方式的构造函数
Date(int year=2022, int month = 2, int day = 20){
_year = year;
_month = month;
_day = day;
}
void date(int year, int month, int day){
this->_year = year;
this->_month = month;
this->_day = day;
}
void Print(){
cout << _year << "/" << _month << "/" << _day <<endl;
}
private:
int _year;
int _month;
int _day;
};
int main(){
Date day1; //注意这种是调用无参构造函数
Date day2(2021,10,19); //带参构造函数
Date day3(); //函数声明,返回一个日期类型的对象
}
Warning:
对象在销毁时会自动调用析构函数,完成类的一些资源清理工作
析构特征:
~
class SeqList
{
public :
SeqList (int capacity = 10)
{
_pData = (DataType*)malloc(capacity * sizeof(DataType));
assert(_pData);
_size = 0;
_capacity = capacity;
}
~SeqList()
{
if (_pData)
{
free(_pData ); // 释放堆上的空间
_pData = NULL; // 将指针置为空
_capacity = 0;
_size = 0;
}
}
private :
int* _pData ;
size_t _size;
size_t _capacity;
};
顾名思义就是拷贝一个一摸一样的对象
特征:
下面就会引发无穷递归,解决办法就是在Date类型后面加一个引用,这里就变成了用别名区分
3. 如果未定义,系统生成默认的 拷贝构造函数。默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝成为浅拷贝
我们先了解一个概念叫运算符重载,具有其返回值类型,函数名以及参数列表
关键字:operator后面接需要重载的运算符符号
Warning:
特征:
4. 参数类型
5. 返回值
6. 检查是否自己给自己赋值
7. 返回*this
8. 一个类如果没有显示定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝
下面就简单实现了日期增加N天的运算符赋值
//Date day(2021,10,10);
//day += 20;
Date& Date::operator+=(int day){
if(day<0){
return *this -= -day;
}else{
_day += day;
//如果日期不合法,进位
while(_day > GetMonthDay(_year, _month)){
_day -= GetMonthDay(_year, _month);
++_month;
if(_month == 13){
++_year;
_month = 1;
}
}
}
return *this;
}
创作不易,如果文章对你帮助的话,最后的最后点赞哦:)