Attention: 1. 本文中的「面向对象」一词属于计算机用语范畴,非人文社科范畴。 2. 虽然本文用c++实现,但是思想在其他语言一样适用。

对于面向对象很多初学者非常不理解:「为啥要这么麻烦的定义类和各种访问限制?」。 这当然与老师的教法很有关系。 我一直认为:「不理解一个东西为何而产生,那么就不能说真的懂这个东西」 所以,在本文我想聊一聊,面向对象思想有何而来,以及运算符重载又是为了什么。

面向对象是什么?

经常听到一句话叫做:一切皆对象。 下面我们来实践下。

面向过程

假设有一天,老板让你实现存储一个平面坐标(x,y)。然后你会怎么做呢? 拍拍脑袋觉得好简单,不就两行代码吗?于是10秒钟解决。给如下代码给老板看。

// 存储坐标(1,1)
int x=1;
int y=1;

然后,老板说:「小明啊,我刚刚想了想,我们要存储100个点行不行?」。卧槽,怎么不早说。100个点我得复制粘贴100次啊,而且还得改变数名。 想想下面这种代码就头痛。

// 存储坐标(1,1)
int x=1;
int y=1;
// 存储坐标(1,1)
int x1=1;
int y1=1;
// 存储坐标(1,1)
int x2=1;
int y2=1;
...//省略n行代码,n>=50
// 存储坐标(1,1)
int x99=1;
int y99=1;

然后,你翻了翻书。发现结构体这个好东西。于是这这么存储100个坐标点。

struct Point{
int x;
int y;
}
Point a[100];

心想:「我简直是天才啊!」,5行代码解决。 然后,->-你老板看了后,想了想。不行啊,我想对坐标进行加法操作。两个坐标都不能相加要它有何用。 然后你就写了一个函数解决这个问题。

struct Point{
int x;
int y;
};
/**
* 返回a和b对应坐标值相加后的坐标
*/
Point add(Point a, Point b){
Point result = Point();
result.x =a.x+b.x;
result.y =a.y+b.y;
return result;
};
...
// 别人调用你代码这样写
Point c = add(a,b);

然后你兴高采烈的告诉老板,你写完了。老板说:「这么快写完了,不错不错」。

运算符重载

心中大舒一口气,想道:「这家伙终于没咋的了」。 然后,程序员B跟你说,你这不直观啊。整数可以a+b这么写,按道理坐标也应该要这么写啊。 你微笑道:「好的,我再改改」。脑海里想到四个词:「万马奔腾」。 然后,百度了下。发现咦用类好像还真可以这么写。然后复制粘贴,写成了下面这行代码。于是你顿悟,为啥要用运算符重载了,因为这样别人用你的代码更直观.

class Point{
public:
int x;
int y;
Point(){
x=0,y=0;
}
Point(int _x,int _y){
x=_x,y=_y;
}
Point operator+(Point b){
Point result = Point(x+b.x,y+b.y);
return result;
}

// 哈哈,同事们这是我留给你们的新特性可以列印坐标
print(){
cout<<"(",x,",",y,")"<<endl;
}
};
...
// 别人调用你代码可以这样写,确实变直观了
Point c = a + b;

继承

有一天,老板决定开新业务。说小明啊,我们想做3D的坐标。可以帮我实现下3维坐标存储和加法么? 你想了想,吸取上次的教训。这次一定得考虑怎么利用原有的代码。不然老是这么不停重写不是办法,头发都得掉光了。 然后去知乎搜下怎么重复利用代码,发现有人告诉你继承可以重复利用代码。 然后,你顿悟。原先是两个维度,我加个维度确实可以继承啊。我就只用写新增那个维度的代码了。 然后改成了这样。

class Point{
public:
int x;
int y;
Point(){
x=0,y=0;
}
Point(int _x,int _y){
x=_x,y=_y;
}
Point operator+(Point b){
Point result = Point(x+b.x,y+b.y);
return result;
}

// 哈哈,同事们这是我留给你们的新特性可以列印坐标
print(){
cout<<"(",x,",",y,")"<<endl;
}
};

// 以下是三维坐标类
class Point_3D : public Point{
public:
//哈哈,x,y在父类已经有了,子类直接继承相当于自己已经定义了x,y. 子类只用管新增的那个维度。
int z;// 新增的一个维度

Point_3D(){
Point();// 重复利用父类的构造函数
z = 0;
}

Point_3D(int _x, int _y, int _z){
z = _z;
Point(_x,_y);
}

// 加法也要改一改
Point_3D operator+(Point_3D b){
//利用父类的运算符重载实现x,y这两个维度的加法
Point_3D result = *this + b;
// 处理新增维度
result.z = z+b;
return result;
}

// 列印的也要改一改
print(){
cout<<"(",x,",",y,",",z,")"<<endl;
}
};

多态

慢慢好像找到感觉了。好像写的有那么点艺术感。 有一天老板说,你给我用一个数组把二维坐标和三维坐标都存在一起。并且还有一次性将他们坐标都列印。 你仰天长啸:「哈哈,开森。终于懂了什么是多态了,多态原来这个用的啊」

Point a[3] = {Point(1,2), Point_3D(1,0,1),Point(0,1)};
// 小B,看我写的代码叼不叼,明明里面有不同类,我同样的代码就正确列印了
// 这就是多态,运行的时候父类会调用父类的print,子类会调用子类的print
for (int i=0;i < 3;i++)
a[i].print();

总结

本文介绍了一些面向对象的思想的出发点,分别是:

运算符重载(为了让别人更直观的用你的代码)

继承(为了少写代码,保留更多的头发)

多态(为了一行代码父类和子类产生不同的效果)

猜你喜欢:

计算机专业大一c++需要刻意去学吗??

www.zhihu.com图标有哪些事实没有一定计算机知识的人不会相信??

www.zhihu.com
图标
计算机生态圈是怎么样的??

www.zhihu.com
图标
Ai酱:神经网路实战:单个神经元+随机梯度下降学习逻辑与规则?

zhuanlan.zhihu.com
图标

推荐阅读:

相关文章