文章主要内容:
1. 面向过程和面向对象
2. 什么是类
3. struct和class关键字
4. 访问权限控制符
5. this指针
一.面向过程和面向对象
相信大家在学校学习C语言的时候,经常会听到学校老师说C语言是一门面向过程的语言,而C++是一门面向对象的语言。那么什么是面向过程?什么又是面向对象?二者究竟有什么区别?我们可以通过一个简单的例子体会以下这二者之间的区别。
问题:把大象放到冰箱里需要怎么做
如果是面向过程:注重的是这个问题需要分几步完成:1.打开冰箱 2.把大象放到冰箱 3.关闭冰箱,面向过程注重的是解决问题每一步需要做什么
而那么如果是面向对象:那么注意点就是我需要放在冰箱里的是一头什么样的大象(对象),我需要准备一个什么样的冰箱,我应该怎么放进去。可以看到,面向对象的思维不在是注重过程,而是把问题分解成不同的对象,处理对象自身的行为和对象之间的联系
那么可以看出,当问题变得很大的时候,面向过程的思想就不是那么合适,而面向对象的思维方式似乎会更好!C++在兼容C语言面向过程式的编程的思想上,又扩充了面向对象的机制,这就是我们要讲的---->类
2.什么是类
前面我们提到了类是C++引入的面向对象的机制,那么类具体是什么呢?简单来讲,类---->是一个框架和模板那么结合生活里的例子,那么我们都知道在平常上实验课的时候。老师都会留一个实验报告的作业
那么我们每个人都要提交一个实验报告,那么老师就会给我们发一份实验报告模板供我们参考.那么类就像是老是给的实验报告模板,我们根据模板可以写出很多的报告,这些报告就是根据类实例化出的对象
3.struct和class关键字
前面我们讲了类的相关概念,那么在C++里面如何定义一个类?这就是我们接下来讲的struct和class关键字
首先,我们来讲一讲比较熟悉的struct关键字。首先,由于C++兼容C语言,所以你仍然可以按照C语言的方式来定义.
//C语言的方式定义
struct A
{
int i;
double d;
}
那么在C++里面,对struct进行了进一步的升级,struct里面还可以有函数。
struct A
{
int i;
double d;
//C++规定还可以定义函数
void Print()
{
cout<<"结构体A"<<endl;
}
};
而且在C++里面,我们可以直接用定义的类名做类型,但是在C语言里面是不允许的,C语言必须加上struct
struct A
{
int i;
double d;
//C++规定还可以定义函数
void Print()
{
cout<<"结构体A"<<endl;
}
};
int main()
{ struct A a;//C语言方式定义
A aa;//C++允许直接这么做
return 0;
}
那么出了struct关键字可以定义类,C++还有一个可以定义类的关键字---->class,使用方式和struct一模一样
//使用class定义类
class A
{
int a;
double d;
void Print()
{
cout<<"A"<<endl;
}
};
那么对于struct和class关键字定义的类,二者的不同的地方仅仅是默认的访问权限不同,那么接下来我们就要讲访问权限。
4.访问权限控制符
那么在C语言里面,结构体的成员是暴露的,也就是外界可以直接操控内部的数据成员,这显然不是我们期望的。那么为了更好的保护数据,C++引入了访问权限控制符来进行数据的封装。这也是面向对象的特性之一
那么访问权限有这三种:
1.public:表示在所有的位置都可以访问
2.private:表示是类的私有成员,只可以在类的内部访问
3.protect:只有在类内和派生类的内部可以直接访问,这里可以直接认为和private等价
那么假如我们实现了一个栈,我不需要你知道我内部实现栈的细节,只提供一些初始化,插入,还有释放的接口给你,那么我就可以这样写:
class MyStack{
public:
void Init(MyStack* ps,int capacity=4)
{
ps->_a=(int*)malloc(sizeof(int)*capacity);
assert(ps->_a);
ps->_top=0;
ps->_capacity=capacity;
}
void Destroy(MyStack* ps)
{
free(ps->_a);
ps->_a=nullptr;
ps->_top=ps->_capacity=0;
}
private:
//成员都用一个_开头区别
int* _a;
int _top;
int _capacity;
};
那么成员函数不仅可以在类内定义,同样还可以在类外定义,不过在类外定义的时候需要使用::来指定函数所属的类
class MyStack{
public:
void Init(MyStack* ps,int capacity=4);
void Destroy(MyStack* ps);
private:
//成员都用一个_开头区别
int* _a;
int _top;
int _capacity;
};
//在类内声明,在类外实现,注意要指明函数属于哪一个类
void MyStack::Init(MyStack* ps,int capacity=4)
{
ps->_a=(int*)malloc(sizeof(int)*capacity);
assert(ps->_a);
ps->_top=0;
ps->_capacity=capacity;
}
void MyStack::Destroy(MyStack* ps)
{
free(ps->_a);
ps->_a=nullptr;
ps->_top=ps->_capacity=0;
}
前面我们提到了struct和class的不同仅仅是默认的访问权限不同。struct关键字的默认访问权限是public,class关键字的默认访问权限是private
4.this指针
假设我有一个日期类,那么这个类有如下的属性
class Date
{
public:
void Init(int year=2022,int month=5,int day=14)
{ _year=year;
_month=month;
_day=day;
}
void Print()
{
cout<<_year<<"-"<<_month<<"-"<<day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.Init();
Date d2;
d2.Init(2022,4,1);
d1.Print();
d2.Print();
}
程序运行结果如下:
这里要注意,成员函数的地址并不是存储在实例化的对象里面的,而是放在公共的代码段。即每个对象调用的都是相同的函数,那么怎么区分每个对象呢?这就是实例化对象在调用成员函数的时候都会隐式传递一个地址参数,这个参数就是this指针
//d1.Print()的等价调用
d1.Print(&d1);//编译器隐式地传递地址
//实际编译器调用函数的处理方式
void Print(Date* this)
注意:this指针参数是由编译器隐式传递,你不能显式的指定!(不要抢编译器的工作)。
总结:
1.面向对象:把问题分解成每个对象,处理对象交互的问题
2.类:造物使用的模板
3.struct和class:定义类的关键字,仅仅是默认访问权限不同
4.访问权限控制符:public,private,protect