先来谈谈什么是面向对象(oop:object oriented programming)
拿做番茄炒鸡蛋为例子。材料:鸡蛋、番茄、油盐等等,做法:放油、放鸡蛋、放番茄、放鸡蛋等等。这就数据和算法。C语言更注重算法,也成为面向过程,自上而下的设计,讲究先讨论是先放鸡蛋还是先放番茄,再讨论怎么放,放多少的问题。
C++呢?更注重数据,也叫自下而上的设计,就是先把放几个鸡蛋都写好,放一个是一个方法,放两个是一个方法,然后你怎么放,直接调用这些方法就行了。所以前人栽树辛苦点,后人乘凉很爽,适合大型的软件设计。
那这就设计到封装,把材料,放多少都放在一个地方,然后后面直接调用就行了,这就是类。类里面包含着数据和操作,比如鸡蛋,然后写上打一个鸡蛋、打两个鸡蛋的方法,取个名,叫鸡蛋及使用;然后在主程序做番茄炒鸡蛋的时候,直接调用鸡蛋类、番茄类等类就行了。而且还可以扩展,加一个韭菜类就可以韭菜煎鸡蛋了。
再来看看定义
- 类包含属性和方法,属性也叫数据成员,方法也叫成员函数。
- 类只是一个概念,比如番茄鸡蛋和韭菜鸡蛋,都是鸡蛋,但是用法不一样,这个时候就需要实例化,生成对象。
- 包含一个或多个构造函数(constructor),用于初始化对象。虽然可以有多个但是只有一个被调用。
- 包含一个析构函数(destructor),用于完成清理工作。
- 构造函数和析构函数也是函数,只是比较特别。没有返回值。名字要和类相同,析构函数是类名前面加~。构造函数可以被重载,可以带参数(不然怎么有多个,名字都要类一样),析构函数不可以(不然怎么只有一个),没有参数。
- 连续定义多个对象时,和局部变量一样, 仿佛压栈,先定义的后析构。
New delete和malloc free 的重要区别
new = malloc+构造;delete = 析构+free;
(对于类多用new和delete,对于基本数据类型没什么区别)
1.malloc/free是C/C++语言的标准库函数,new/delete是C++的运算符。
2.new能够自动分配空间大小。
类的初始化
三种方案:显式 、隐式、构造+析构。
如果我们不写构造函数,系统会提供一个默认无参构造函数,什么都不干。不写拷贝构造函数,系统也会提供一个默认拷贝函数,称为浅拷贝,主要初始化下成员变量,其实也基本什么都没干。我们可以自己设定拷贝构造函数,称为深拷贝,来初始化成员变量。
值得注意的是:只要写了构造函数就必须用,系统不会再给默认的方式。
#include <iostream>
using namespace std;
class Test88
{
public:
//自己写,显式,这不是构造函数,放着构造函数不用是不是傻。
void init(int a = 0, int b = 0)
{
m_a = a;
m_b = b;
}
//有参构造函数
Test88(int a)
{
m_a = a;
}
//无参数构造函数
Test88()
{
m_a = 0;
}
//赋值构造函数 copy构造函数
Test88(const Test88 &obj)
{
cout<<"GouZao"<<endl;
m_a = obj.m_a;
}
~Test88()
{
cout << "XiGou" <<endl;
}
public:
void Testprint()
{
cout<<"m_a"<<m_a<<endl;
}
int GetA() { return m_a ; }
int GetB() { return m_b ; }
void SetA(int a) { m_a = a; }
void SetB(int b) { m_b = b; }
private:
int m_a;
int m_b;
};
void f ( Test88 p ) //运行完后,会调用析构函数释放形参
{
cout << "Funtion:" << p.GetA() << "," << p.GetB() << endl ;
}
Test88 g()
{
Test88 A(1);
return A;
//A是局部的,在其析构前C++编译器创建了一个匿名对象用于接受A对象的数据。
//赋值完后,A消失 --- 匿名对象消失 ---- T4消失
}
int main()
{
Test88 b1,b2,b3;
//显示的初始化对象
b1.init();
b2.init();
b3.init();
Test88 Array[3] = { b1, b2, b3 };
for (int i=0;i<3;i++)
{
cout << Array[i].GetA() << endl;
}
///////////////////////////////////////////////
Test88 t1; //默认的就是无参的
t1.SetA(1);
t1.Testprint();
//拷贝构造函数的四种应用场景
//第一种,赋值构造函数(和=操作是两个不同的概念)
Test88 t2 = t1;
t2.Testprint();
//第二种,用t1初始化t2,和第一种差不多
Test88 t3(t1);
t3.Testprint();
//第三种,实参去构造形参
Test88 t4(30);
f(t4);
t4.Testprint();
//第四种,返回值构造
Test88 t5;
t5 = g(); //此时用的是浅拷贝,就是=操作
t5.Testprint();
t2 = t1; //是对象的=操作,系统提供的浅拷贝
return 0;
}