一、面向过程编程 与 面向对象编程
1、面向过程编程
首先考虑遵循的步骤,然后考虑如何表示这些数据
2、面向对象编程
首先从用户的角度考虑对象——描述对象所需的数据以及描述用户与数据交互所需的操作。
完成对接口的描述后,需要确定如何实现接口和数据存储。
二、面向对象的特点
封装:按照信息屏蔽的原则,把对象的属性和操作结合在一起,构成一个独立的对象
通过限制对属性和操作的访问权限,将数据进行隐藏,把不想让外部使用的数据状态
隐藏起来;
继承:实现代码复用;
多态:同一个消息被不同的对象接收时,产生不同结果,即实现同一接口,不同方法(实现功能的扩展);
三、抽象和类
抽象:将问题的本质抽取出来,并根据特征来描述解决方案
类:类是一种将抽象转化为用户定义类型的C++工具,他将数据的表示和操纵的方法组合成一个整洁的包。
在C++中,结构体内部允许设置访问权限,默认访问权限是公有,而类的默认访问权限是私有
定义一个结构体,可以直接用" = "进行初始化,但类只能使用构造函数进行初始化
类的内部成员 (变量和函数) 访问权限: 3种 public private protected
public:公有属性,类的内部和外部都可以访问
protected:保护属性,类的内部可以访问,外部不可以访问
private:私有属性,类的内部和外部都不可以访问
四、构造函数和析构函数
构造函数:函数名与类名相同,函数没有返回值;构造函数在定义时可以有参数
构造函数在一般情况下,不需要手动调用,系统自动调用,初始化对象的时候调用
析构函数:函数名和类名相同,函数前加一个~,析构函数没有返回值
回收对象资源,当对象被释放的时候,系统自动调用析构函数回收对象资源
构造函数是可以被重载的,析构函数不可重载
构造函数又分为无参构造、有参构造
构造函数被调用的方式:
1、括号
Test1_1 t1(10);
Test1_1 t2(1,2);
2、等号
Test1_1 t3 = 4; // ===> Test1_1 t3(4);
t3.print();
Test1_1 t4 = (2,3); // =====> Test1_1 t4(3);
t4.print();
3、手动调用
Test1_1 t5 = Test1_1(); // Test1_1 t5;
t5.print();
Test1_1 t6 = Test1_1(1,2); // Test1_1 t6(1,2);
t6.print();
对象的初始化与对象的赋值不同
Test t1(4,5);
Test t2 = Test(5,6); // 对象的初始化
t2 = t1; // 对象的赋值
用一个对象去对另一个对象初始化会调用拷贝构造函数
Test1_1 t3(t2); // ====> Test1_1(const Test1_1 &obj);
t3.print();
Test1_1 t4 = t3; // Test1_1 t4(t3); 调用拷贝构造函数
t4.print();
Test1_1 t5 = Test1_1(t1); // 拷贝构造函数调用
t5.print();
传对象的时候 要传对象的引用或指针 否则调用对象的拷贝构造函数
对象做函数返回值
1、不接受返回值,产生的匿名对象会立马被释放
2、用匿名对象初始化 t , t 不会开空间,直接使用匿名对象的空间
3、用一个已经存在的对象去接收函数返回的对象,产生一个匿名对象,
用返回的对象对其进行初始化,调用拷贝构造函数,用匿名对象对当前
对象进行赋值,赋值完之后,匿名对象被释放
默认构造函数
如果类中一个构造函数都没有,编译会默认添加一个无参的构造函数,这个构造函数 函数体是空
如果类中没有析构函数,编译会默认添加一个析构函数, 函数体是空
类中一旦有构造函数(任何形式的构造函数 包括拷贝构造), 编译器将不会提供无参构造函数
如果类中没有定义拷贝构造函数,编译器默认会添加一个拷贝构造函数,这个进行变量 "值" 的复制
五、浅拷贝和深拷贝
浅拷贝:“ 值 ”的拷贝,不会复制堆上的空间
深拷贝:自己编写拷贝构造函数,实现堆上的复制
解决浅拷贝的方案:手动编写拷贝构造函数,进行深拷贝
浅拷贝的时候,很可能初始化的时候两个对象的指针变量指向
同一块地址,因此析构的时候会对0x1000这块地址释放两次
而深拷贝不会,会调用自己的拷贝构造函数,在函数体内会开辟空间
这样两个对象就指向不同的地址