• 正在加载中...
  • ”是个多义词,全部含义如下:

    纠错 | 编辑多义词

    类[编程术语]

    类(Class)是面向对象程序设计(OOP,Object-Oriented Programming)实现信息封装的基础。类是一种用户定义类型,也称类类型。每个类包含数据说明和一组操作数据或传递消息的函数。类的实例称为对象。

    编辑摘要

    目录

    介绍/类[编程术语] 编辑

    一个简单的类图 一个简单的类图

    类是面向对象程序设计中的概念,是面向对象编程的基础。

    类的实质是 一种数据类型,类似于int、char等基本类型,不同的是它是一种复杂的数据类型。因为它的本质是类型,而不是数据,所以不存在于内存中,不能被直接操作,只有被实例化为对象时,才会变得可操作。

    类是 对现实生活中一类具有共同特征的事物的抽象。如果一个程序里提供的类型与应用中的概念有直接的对应,这个程序就会更容易理解,也更容易修改。一组经过很好选择的用户定义的类会使程序更简洁。此外,它还能使各种形式的代码分析更容易进行。特别地,它还会使编译器有可能检查对象的非法使用。 [1] 

    类的内部封装了方法,用于操作自身的成员。类是对某种对象的定义,具有行为(be-havior),它描述一个对象能够做什么以及做的方法(method),它们是可以对这个对象进行操作的程序和过程。它包含有关对象行为方式的信息,包括它的名称、方法、属性和事件。

    类的构成包括数据成员和成员函数。数据成员对应类的属性,类的数据成员也是一种数据类型,并不需要分配内存。成员函数则用于操作类的各项属性,是一个类具有的特有的操作,比如“学生”可以“上课”,而“水果”则不能。类和外界发生交互的操作称为接口。

    用法/类[编程术语] 编辑

    定义一个类

    公有成员、私有成员、保护成员均包含数据成员和成员函数两部分,彼此没有顺序之分。一个public/private/protected关键字下可以跟多个成员,直到下一个public/private/protected关键字。如果成员前面没有public/private/protected关键字,默认为私有成员。

    结尾部分的分号必不可少,否则会发生语法错误。

    无论公有成员、私有成员还是保护成员,彼此之间都可以访问。比如公有的成员函数可以操作保护的数据成员,也可以调用私有的成员函数。

    类的数据成员是类型,所以不能被赋值,声明数据成员和声明普通变量的格式相同,比如“int n;”。

    1.

    公有成员、私有成员、保护成员均包含数据成员和成员函数两部分,彼此没有顺序之分。一个public/private/protected关键字下可以跟多个成员,直到下一个public/private/protected关键字。如果成员前面没有public/private/protected关键字,默认为私有成员。

    2.

    结尾部分的分号必不可少,否则会发生语法错误。

    3.

    无论公有成员、私有成员还是保护成员,彼此之间都可以访问。比如公有的成员函数可以操作保护的数据成员,也可以调用私有的成员函数。

    4.

    类的数据成员是类型,所以不能被赋值,声明数据成员和声明普通变量的格式相同,比如“int n;”。

    成员函数的实现

    成员函数可以在类内实现,也可以在类外实现。内部实现的成员函数被默认为加上了inline;外部实现的成员函数必须加上域操作符,即“类名::成员函数”。

    构造函数与析构函数

    构造函数和析构函数是特殊的成员函数,和普通成员函数不同的地方在于:

    函数名固定

    构造函数和析构函数的函数名必须是类名。

    声明格式不同

    构造函数和析构函数没有返回值,连空返回值——void也没有。

    构造函数的声明形式:类名(参数列表);

    析构函数的声明形式:~类名();

    重载的特殊性

    构造函数和普通成员函数一样可以被重载,析构函数不可以重载,只能是空参数。

    调用过程不同

    构造函数和析构函数不能被显式地调用,只能由编译器自动调用。

    1.

    函数名固定

    构造函数和析构函数的函数名必须是类名。

    2.

    声明格式不同

    构造函数和析构函数没有返回值,连空返回值——void也没有。

    构造函数的声明形式:类名(参数列表);

    析构函数的声明形式:~类名();

    3.

    重载的特殊性

    构造函数和普通成员函数一样可以被重载,析构函数不可以重载,只能是空参数。

    4.

    调用过程不同

    构造函数和析构函数不能被显式地调用,只能由编译器自动调用。

    构造函数用于创建类的对象,任何创建对象的行为,都会导致构造函数被调用。析构函数和构造函数的功能相反,析构函数用于销毁对象,当类的对象超出作用域被销毁时,析构函数被调用。

    即使显式地定义构造函数和析构函数,也还是会有默认的构造函数和析构函数,函数内部无任何语句,不执行任何操作。默认构造函数是无参数的。需要注意的是,一旦显式定义任意形参的构造函数,默认构造函数都不会生成,即只有没有定义构造函数的类才存在默认构造函数。

    一般情况下,默认的构造函数和析构函数可以满足功能需要,然而当需要重载构造函数,或是需要动态分配资源的时候,就不得不定义自己的构造函数甚至析构函数了。

    拷贝构造函数是特殊的构造函数,在复制对象时被调用,定义的格式为“类名(类名& 参数名)”。拷贝构造函数也存在默认的,但很多情况下都需要重载。

    类的实例化

    就像声明某种类型的变量一样,声明一个类类型的对象,就是类的实例化,会涉及到必要的内存分配。

    不同语言中类的实例化形式是不同的。

    C++

    类名 对象名(参数列表);

    如果没有参数,括号必须省略,即“类名 对象名;”,自动调用构造函数。特殊地,参数可以是类的对象,此时会自动调用拷贝构造函数。

    Java/C#

    类名 对象名 = new 类名(参数列表);

    括号不能省略。

    1.

    C++

    类名 对象名(参数列表);

    如果没有参数,括号必须省略,即“类名 对象名;”,自动调用构造函数。特殊地,参数可以是类的对象,此时会自动调用拷贝构造函数。

    2.

    Java/C#

    类名 对象名 = new 类名(参数列表);

    括号不能省略。

    对象可以访问类的成员,但并不是所有成员都可以被访问,能否访问取决于声明该成员时所用的关键字(public/protected/private)。具体规则如下:

    类的公有成员可以被该类,其派生类和类实例化的对象访问。

    类的保护成员可以被该类及其派生类访问,不可以被该类的对象访问。

    类的私有成员可以被该类访问,不可以被派生类及其该类的对象访问。

    1.

    类的公有成员可以被该类,其派生类和类实例化的对象访问。

    2.

    类的保护成员可以被该类及其派生类访问,不可以被该类的对象访问。

    3.

    类的私有成员可以被该类访问,不可以被派生类及其该类的对象访问。

    派生与继承

    子类即是继承而来的类,父类即是被继承的类,或者称之为基类。

    public修饰的为公有继承,private修饰的为私有继承,protected修饰的为保护继承。

    父类可以只有一个,也可以有多个。只有一个父类称为单继承,多个父类称为多继承。C++支持多继承的机制,Java则只具有单继承功能,并增加了“接口”的概念,一个类可以实现多个接口。

    如果不标明继承方式,默认为私有继承。

    1.

    子类即是继承而来的类,父类即是被继承的类,或者称之为基类。

    2.

    public修饰的为公有继承,private修饰的为私有继承,protected修饰的为保护继承。

    3.

    父类可以只有一个,也可以有多个。只有一个父类称为单继承,多个父类称为多继承。C++支持多继承的机制,Java则只具有单继承功能,并增加了“接口”的概念,一个类可以实现多个接口。

    4.

    如果不标明继承方式,默认为私有继承。

    派生和继承是类的重要特性,继承是由抽象到具体的体现。通过继承,子类可以使用父类的成员。

    但要注意的是,派生和继承在带来方便的同时,也会使类与类之间的关系变得复杂,尤其是涉及到私有继承和保护继承时,类中成员的关系可能会变得难以理解。所以在涉及类时,尽量避免过多层次的继承,私有继承和保护继承的使用也要慎重。

    继承来的成员和自身声明的成员并无本质区别,也有公有成员、私有成员、保护成员之分。继承时,父类中成员类型(公有成员/私有成员/保护成员)和继承方式(公有继承/私有继承/保护继承)不同,情况不同。可以归纳为:

    三种类型的继承,父类的成员均被子类继承(之前的百科关于这点的描述是错误的),只是由类实例化的对象对其继承的成员的访问权限会有所变化。三种不同方式的继承,描述的是子类实例化对象对其成员的访问权限,并非是描述子类时,子类对继承自父类的成员的访问权限。

    公有继承

    继承自父类的成员保持不变。

    私有继承

    继承自父类的成员全部变为私有成员。

    保护继承

    继承自父类的公有成员变为保护成员,其余不变。

    1.

    公有继承

    继承自父类的成员保持不变。

    2.

    私有继承

    继承自父类的成员全部变为私有成员。

    3.

    保护继承

    继承自父类的公有成员变为保护成员,其余不变。

    操作符重载

    操作符重载必须在类中进行,重载操作符可以使操作符对在类中的语义发生变化。除了. ,.* ,:: ,? : 、sizeof、typeid这几个运算符不能重载之外,大部分运算符都能被重载。但要注意,重载操作符并不能改变操作符的优先级和结合律,而且从认知规律上讲,重载的操作符功能必须与原意相近,否则很难被人理解。

    操作符重载是函数,在使用该操作符时被调用。操作符重载函数的声明形式:返回值 operator操作符(参数列表);

    友元

    友元可以是函数,被称为友元函数;也可以是类,被称为友元类。

    通常,类中的私有成员只能被自身使用,无法被它的对象访问。因此,另一个类即便可以使用该类的对象,也无法访问该类的私有成员,通过定义友元的方法可以做到这一点。

    友元就是在一个类中“再次声明”另一个类的成员函数或是另一个类,被“再次声明”的成员函数或类可以访问该类的私有成员。这种“再次声明”并不是普通的声明,格式为:friend 函数/类名;

    显然,友元会破坏类的封装性,使本该隐藏的成员暴露出来,因此应当谨慎使用。

    组合

    继承可以描述“交通工具”和“公交车”的关系,却无法描述“公交车”和“车轮”的关系。

    大多数“车轮”具有的特性是“公交车”所不具有的。比如说“车轮”具有“重量”,而“公交车”的“重量”则是另一个含义。而通过私有成员、保护成员机制控制这些成员的继承性,会使继承变得复杂而难以理解。而且

    继承来的数据成员只有一个,而一辆“公交车”却有四个“车轮”,四个“车轮”的“重量”。

    1.

    大多数“车轮”具有的特性是“公交车”所不具有的。比如说“车轮”具有“重量”,而“公交车”的“重量”则是另一个含义。而通过私有成员、保护成员机制控制这些成员的继承性,会使继承变得复杂而难以理解。而且

    2.

    继承来的数据成员只有一个,而一辆“公交车”却有四个“车轮”,四个“车轮”的“重量”。

    引入组合的概念,“公交车”完全可以由“车轮”、“方向盘”、“车身”等类组合而来。方法就是将类当成其他的数据类型一样,在另一个类中定义该类类型的数据成员。

    抽象类

    并不是所有种类的事物都可以被实例化,换而言之,有的种类只是一种抽象概念,现实中并没有实际存在的对应物。比如:假设所有的动物都会叫,我们可以定义一个类——“动物”,定义类中的一个成员函数——“叫”,我们知道猫的叫声,也知道狗的叫声,然而“动物”是如何“叫”的?——我们根本无法实现它。所以,我们引入了抽象类的概念,抽象类是无法被实例化的,无法声明抽象类的对象。

    通常,用 abstract 修饰的类是抽象类;C++中包含纯虚函数的类是抽象类;Java中含有抽象方法的类是抽象类;继承了纯虚函数而没有实现它的类也是抽象类。

    抽象类只能被用作基类,作用体现在:

    约束派生类必须实现的成员函数或方法。

    不同派生类中同名的成员函数实现不同,体现了多态性。

    1.

    约束派生类必须实现的成员函数或方法。

    2.

    不同派生类中同名的成员函数实现不同,体现了多态性。

    静态成员

    用static修饰的成员是静态成员,可以是成员函数或数据成员。静态成员是所有对象共有的,只分配一次内存,产生新的对象时不会产生副本。

    静态数据成员的初始化必须在类外进行,使用静态成员时必须使用类名和域操作符。

    特性/类[编程术语] 编辑

    类的三大特性

    封装性

    将数据和操作封装为一个有机的整体,由于类中私有成员都是隐藏的,只向外部提供有限的接口,所以能够保证内部的高内聚性和与外部的低耦合性。用者不必了解具体的实现细节,而只是要通过外部接口,以特定的访问权限来使用类的成员,能够增强安全性和简化编程。

    继承性

    继承性更符合认知规律,使程序更易于理解,同时节省不必要的重复代码。

    多态性

    同一操作作用于不同对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。

    1.

    封装性

    将数据和操作封装为一个有机的整体,由于类中私有成员都是隐藏的,只向外部提供有限的接口,所以能够保证内部的高内聚性和与外部的低耦合性。用者不必了解具体的实现细节,而只是要通过外部接口,以特定的访问权限来使用类的成员,能够增强安全性和简化编程。

    2.

    继承性

    继承性更符合认知规律,使程序更易于理解,同时节省不必要的重复代码。

    3.

    多态性

    同一操作作用于不同对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。

    与结构体的区别

    在C++、C#语言中,class和struct都可以定义一个类,它们的区别如下:

    C#中,class是引用类型,继承自System.Object类;struct是值类型,继承自System.ValueType类,不具多态性。但是注意,System.ValueType是个引用类型。

    从职能观点来看,class表现为行为;而struct常用于存储数据。

    class支持继承,可以继承自类和接口;而struct没有继承性,struct不能从class继承,也不能作为class的基类,但struct支持接口继承。

    class可以声明无参构造函数,可以声明析构函数;而struct只能声明带参数构造函数,且不能声明析构函数。因此,struct没有自定义的默认无参构造函数,默认无参构造器只是简单地把所有值初始化为它们的0等价值。

    Java/C#中,实例化时,class要使用new关键字;而struct可以不使用new关键字,如果不以new来实例化struct,则其所有的字段将处于未分配状态,直到所有字段完成初始化,否则引用未赋值的字段会导致编译错误。

    class可以实现抽象类(abstract),可以声明抽象函数;而struct为抽象,也不能声明抽象函数。

    class可以声明protected成员、virtual成员、sealed成员和override成员;而struct不可以,但是值得注意的是,struct可以重载System.Object的3个虚方法,Equals()、ToString()和 GetHashTable()。

    class的对象复制分为浅拷贝和深拷贝,必须经过特别的方法来完成复制;而struct创建的对象复制简单,可以直接以等号连接即可。

    class实例由垃圾回收机制来保证内存的回收处理;而struct变量使用完后立即自动解除内存分配。

    作为参数传递时,class变量是以按址方式传递;而struct变量是以按值方式传递的。

    1.

    C#中,class是引用类型,继承自System.Object类;struct是值类型,继承自System.ValueType类,不具多态性。但是注意,System.ValueType是个引用类型。

    2.

    从职能观点来看,class表现为行为;而struct常用于存储数据。

    3.

    class支持继承,可以继承自类和接口;而struct没有继承性,struct不能从class继承,也不能作为class的基类,但struct支持接口继承。

    4.

    class可以声明无参构造函数,可以声明析构函数;而struct只能声明带参数构造函数,且不能声明析构函数。因此,struct没有自定义的默认无参构造函数,默认无参构造器只是简单地把所有值初始化为它们的0等价值。

    5.

    Java/C#中,实例化时,class要使用new关键字;而struct可以不使用new关键字,如果不以new来实例化struct,则其所有的字段将处于未分配状态,直到所有字段完成初始化,否则引用未赋值的字段会导致编译错误。

    6.

    class可以实现抽象类(abstract),可以声明抽象函数;而struct为抽象,也不能声明抽象函数。

    7.

    class可以声明protected成员、virtual成员、sealed成员和override成员;而struct不可以,但是值得注意的是,struct可以重载System.Object的3个虚方法,Equals()、ToString()和 GetHashTable()。

    8.

    class的对象复制分为浅拷贝和深拷贝,必须经过特别的方法来完成复制;而struct创建的对象复制简单,可以直接以等号连接即可。

    9.

    class实例由垃圾回收机制来保证内存的回收处理;而struct变量使用完后立即自动解除内存分配。

    10.

    作为参数传递时,class变量是以按址方式传递;而struct变量是以按值方式传递的。

    我们可以简单的理解,class是一个可以动的机器,有行为,有多态,有继承;而struct就是个零件箱,组合了不同结构的零件。其实,class和struct最本质的区别就在于class是引用类型,内存分配于托管堆;而struct是值类型,内存分配于线程的堆栈上。由此差异,导致了上述所有的不同点。所以只有深刻的理解内存分配的相关内容,才能更好的驾驭。

    当然,使用class基本可以替代struct的任何场合,class后来居上。虽然在某些方面struct有性能方面的优势,但是在面向对象编程里,基本是class横行的天下。

    那么,有人不免会提出,既然class几乎可以完全替代struct来实现所有的功能,那么struct还有存在的必要吗?答案是,至少在以下情况下,鉴于性能上的考虑,我们应该考虑使用struct来代替class:

    实现一个主要用于存储数据的结构时,可以考虑struct。

    struct变量占有堆栈的空间,因此只适用于数据量相对小的场合。

    struct数组具有更高的效率。

    1.

    实现一个主要用于存储数据的结构时,可以考虑struct。

    2.

    struct变量占有堆栈的空间,因此只适用于数据量相对小的场合。

    3.

    struct数组具有更高的效率。

    示例/类[编程术语] 编辑

    类的复用

    添加视频 | 添加图册相关影像

    开放分类 我来补充

    互动百科的词条(含所附图片)系由网友上传,如果涉嫌侵权,请与客服联系,我们将按照法律之相关规定及时进行处理。未经许可,禁止商业网站等复制、抓取本站内容;合理使用者,请注明来源于www.baike.com。

    登录后使用互动百科的服务,将会得到个性化的提示和帮助,还有机会和专业认证智愿者沟通。

    互动百科用户登录注册
    此词条还可添加  信息模块

    WIKI热度

    1. 编辑次数:3次 历史版本
    2. 参与编辑人数:3
    3. 最近更新时间:2019-06-04 16:58:21

    贡献光荣榜

    更多

    相关词条

    互动百科

    扫码下载APP