面向对象和面向过程编程初步认识
C语言是面向过程的,关注过程(分析求解问题的步骤)
例如:外卖,关注点菜,接单,送单等
C++是面向对象的,关注对象,把一件事拆分成不同的对象,对每个对象进行分别管理,依靠对象之间的交互完成。例如:外卖,关注用户,骑手,商家三个核心对象,三者交互完成这件事
文章目录
- 类的引入
- 访问限定符
- 类域
- 类的大小(sizeof)
- this指针
- 构造函数
- 析构函数
- 拷贝构造
类的引入
在C语言中有结构体(struct)的概念,C++是兼容了struct在C语言中的用法,同时增加了结构体中实现函数功能,为了区别结构体C++引入了新的关键字class——类,
类中的内容是类的成员,变量叫做成员变量或类的属性,函数叫做成员函数或类的方法
C++中类和结构体基本上的用法是相同的
注意:
变量的定义是指开空间,类中的成员变量都是声明,对象实例化时,才是定义
class Date {
int _year;
int _month;
int _day;
};
这是一个简单的日期类
也可以写作
struct Date2 {
int _year;
int _month;
int _day;
};
上述代码访问d1._year 报错了,d2._year却没有
这就要说到访问限定符了
访问限定符
C++有三种访问限定符,public,private,protected
就是限制对类中的成员进行访问,
public(公有)类里面和外面都可以使用
private(私有)只有类里面可以使用,
protected 先不考虑
class 和 struct 的主要的区别就在这里:
class 不加访问限定符就默认表示私有
struct 默认表示公有
这就是为什么上述代码报错,加上public限定符修饰就可以在外面访问成员变量了
加上这样的修饰就可以访问了,
public:这样就是修饰为公有,范围到下一个访问限定符或者结尾。
一般情况下成员变量都是私有的,不希望直接访问或修改成员变量,而是通过函数调用来修改
类域
我们想要对类中的函数进行声明定义分离,该如何操作呢
看下面代码
class Date {
public:
void print();
int _year;
int _month;
int _day;
};
void print()
{
_year = 1, _month = 1, _day = 1;
cout << _year << '-' << _month << '-' << _day << endl;
}
int main()
{
Date d1;
d1.print();
return 0;
}
上述打印功能函数会直接报错,这里就要了解类域
类定义了一个新的作用域,类的所有成员都在类的作用域中,类外定义成员时需要使用 :: 操作
正确代码应该是
void Date::print()
{
_year = 1, _month = 1, _day = 1;
cout << _year << '-' << _month << '-' << _day << endl;
}
这样就可以了
类的大小(sizeof)
类中成员函数的功能都是一样的,所以类里面只存成员变量,成员函数存在一个公共的区域(代码段),每个对象里面都放成员函数太冗余了(每创建一个类,都为函数开辟空间太浪费)
没有成员变量的类大小为 1byte,为了表示这个对象存在过。
遵循结构体内存对齐规则(空间换时间,提高效率)
this指针
上述打印日期时,我们没有传入参数,但是能打印出结果,
class Date {
public:
//构造函数初始化,先不用管
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
void print()
{
cout << this->_year << '-' << _month << '-' << _day << endl;
}
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2005, 8, 27);
Date d2(2004, 8, 27);
d1.print();
d2.print();
return 0;
}
运行结果如下
可以通过this指针来找到d1中的成员变量,this指针编译时编译器会自动不上,不写也可以,但注意的时,this在函数中可以使用,不能传参。this指针相当于 &d1,this指针是形参,对&d1的拷贝,存在于栈区
面向对象的三大特性:封装,继承,多态
封装的本质是一种管控,把数据和方法都放在类里面,通过访问限定符对成员变量进行限制,也更便于维护
先来看封装
构造函数
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
上述代码中,这个函数可以对日期类成员变量进行初始化。
这就是一个构造函数,主要任务是初始化对象。
构造函数有以下几个特性
1、函数名与类名相同
2、无返回值
3、对象实例化时自动调用,不需要自己操作
'4、构造函数可以重载
5、如果没有写构造函数,构造函数可以自动生成一个构造函数,但是它不做任何事情
6、编译器自动生成的构造函数(内置类型不做任何处理,自定义类型去调用它的构造函数)
无参数,全缺省,自动生成的都是默认构造函数,一般建议提供全缺省构造函数
绝大多数情况下,要自己写构造函数,只要写了一个,编译器就不会默认生成了(一般构造函数写成全缺省的最方便)
析构函数
析构函数:清理资源
~类名()
1、没有返回值,没有参数
2、函数结束自动执行析构函数,清理资源
3、析构函数也可以默认生成,功能和构造函数类似。
析构函数只有一个,不能被重载
拷贝构造
拷贝构造函数:
传参要传引用,否则会无穷递归(传参本身就会产生形参,形参又要调用拷贝构造函数,从而形成无限递归)
拷贝构造是默认成员函数,如果没有显示定义,会默认生成拷贝构造函数
内值类型:浅拷贝(值拷贝)
自定义类型:调用拷贝构造函数
成员变量中有数组指针,就需要进行深拷贝
默认生成的拷贝构造不能实现深拷贝