6.结构体、类、接口

一、前言

本文介绍一个编程语言中非常通用的概念,也就是结构体接口这三个东西。

虽然各种编程语言中对它们的命名不一定一致,但其本质其实都是如此。

二、结构体

结构体,在C/C++语言中经常看到,其它语言中也常有,比如rustgo,而且基本都是用的关键字struct来命名。

它的基本作用就是将一些相关的属性联合到一起,比如一个经典的例子就是学生

一个学生是可以有很多属性的,比如姓名、性别、学号、成绩等等等等。

如果不将这些相关的属性进行联合,就会导致使用起来非常混乱,以C/C++代码为例:

string name1="小明";//学生1
int age1=10;

string name2="小红"; //学生2
int age2=20;

如果编程语言本身不提供将属性联合起来的功能(比如汇编语言似乎就没有这种功能),那么你就不得不这样分开写每个学生的信息,非常的麻烦,并且不直观。

而结构体这个功能就允许我们任意组合属于自己的类型:

struct Stu{
	string name;
	int age;
}
//使用
Stu s1; //学生1
s1.name="小明";
s1.age=10;

此时s1的类型为我们自定义的Stu类型,其中就组合了一个学生的基本信息,这样在使用起来就会非常的方便,符合我们一贯的直觉操作。

三、类

结构体虽然好,但也有不足,因为现实世界中,一个对象不仅仅有属性,也会有行为。

还是以上面的那个学生为例,如果我想要打印每个学生自己的姓名、年龄,一般就会像下面这样做:

void print(Stu s){
	printf("%s,%d\n",s.name.data(),s.age);
}
Stu s1; //学生1
s1.name="小明";
s1.age=10;
print(s1);

即:定义一个函数,专门来打印这个结构体,需要的时候调用就行了。

但此时你会发现,此时这个print函数参数被固定为了Stu类型,这意味着,这个函数只能被用于这个结构体。

既然如此,那为什么不让结构体把这个函数也组合进去呢?

这就可以被称为了,一般都是以关键字class来定义的:

class Stu{
public:
	string name;
	int age;
	void print(){
        printf("%s,%d\n",name.data(),s.age);
    }
}

一般高级语言都会有类的概念,比如C++、python、Java等等,其中Java更是其中的极端代表,以万物皆对象为基本理念,即使是最基本的数据类型,比如int类型的数字,在Java中都是一个类。

类的基本理念其实就是将属性、行为封装到了一起,这符合人一贯的现实世界直觉:

Stu s1; //学生1
s1.name="小明";
s1.age=10;
s1.print(); //调用这个对象上的行为、也就是方法、函数,

当然,这仅是类的基本内容,更多的还有继承、权限、多态等概念。

但事实上,有了上面的基本知识,你就已经完成能够开始正常写代码了。

而这些继承权限多态等概念,其本质上都只是在进一步简化代码提升代码安全性而已,即使不用,你也一样可以写代码。

但这涉及到了各种语言的细节,这里就不再过多赘述了。

四、接口

相比于结构体、类这种各种语言都很统一的概念,接口就很有意思了, 因为它在各种语言中的概念都不是很统一,但其本质上又都代表了一种东西:方法的集合

比如Java中专门有一个声明接口的关键字:Interface

go中的关键字与之相同:interface

rust语言有个类似的东西为Trait,即特性、特征的意思,声明关键字为:trait

C++中有个概念叫做纯虚类,使用方式就是一个类中的所有方法都是虚函数:virtual

可以看到,在现代语言中,基本都会有接口这种概念,但并不一定会有类的概念。

比如go、rust,这两个本身是没有类的概念的,但可以通过其它方式来实现类的功能。

它的主要作用在于抽象一个方法集合,便于程序员使用与实现。

举个例子,车会跑、动物会跑,这两个虽然一看就不是一类的,但都可以

再进一步抽象一下,这个行为本身,其实就是物体有速度,那么此刻你就发现,几乎任何东西都可以有这个行为了。

但此时采取以往的方式,就会出现一个问题,比如我们想要定义一个跑的函数,那么车、动物你可能使用的函数名是:run,而飞机你使用的函数名大概率就是flight了,又或者海生动物那就是swimming

这缺乏通用性,如果作为用户想要使用某个类,就必须研究一下这个类有哪些特性才行,但类是多变的,就会导致这个过程是耗时的。

而接口就不一样了,上面的一切行为我都可以定义为一个move的函数名,都是在移动嘛!

然后我可以将这个接口命名为MoveAct,即移动行为的意思。

而这些结构体,就不用单独实现自己的runflightswimming等方法了,而是可以直接来实现这个MoveAct接口,进而也就需要来实现其中这个move函数的内容。

此时用户一看你类实现了这个MoveAct接口,那还有必要看你类是怎么实现的吗?完全没必要嘛!

我们只需要看一下这个MoveAct接口里面有哪些方法,只要你的类、结构体使用了这个接口,那就必然有这个方法,此时我就完全不用管你这个类是怎么实现的了!

因为无论是什么类,最后都是通过move这个函数来完成移动这个行为的!

在rust中将其定义为Trait,即特性,这也是一个很符合感觉的概念,因为事实上确实如此,这些行为本身就可以看作一个有一个特性,即使是不同类,也是可以有同一种特性的!

五、简单总结

本文并没有具体讨论各种语言本身实现结构体、类、接口这三者的技术细节以及使用方式,而是更加侧重于从总体上感受、理解这三者的缘由与关系。

简单来说就是:

  • 结构体:属性的集合
  • 接口:方法的集合
  • 类:属性与方法共同的集合

结构体不用说,这是必然需要的,因为我们有集合各种属性的需求。

这个概念,如今其实已经在慢慢势颓了,如今很火的gorust等新兴语言,已经不再原生支持类了。

大家不约而同的都在向接口这个概念开始转变,甚至Java这个原本以类为基石的语言,如今都已经开始被戏称为面向接口编程的语言了。

作者:余识
全部文章:0
会员文章:0
总阅读量:0
c/c++pythonrustJavaScriptwindowslinux