Different_对象和类
大约 8 分钟
Different_对象和类
概念区别,什么是类 / 对象 / 面向对象语言
各语言中,什么是类 / 对象 / 面向对象语言
什么是类?
(结合下一节一起看)
- 类:我个人认为只要能将数据和方法绑定在一起,且能实现面向对象三大特性 (封装/继承/多态),都能称之为类。
- Class类 (大多数语言,如C++、Java、C#):用 Class 关键字声明类,这是传统的类
- Struct类 (C++/C、Go、Rust):有的语言用 Struct 当作类,或允许 (C++、Go) 或不允许 (C) 数据和方法定义在一起 (C++结构体在C的基础上支持了方法的定义,但似乎一般不叫这个为类,也一般不这样用)
- 原型类 (JavaScript):一个对象的原型相当于实例化自己的类,原型链上有自己的类、父类及祖先类 (在ES6及以后的版本中,JavaScript引入了 class 关键字,它提供了一种更接近传统面向对象语言的语法糖,但本质上仍然是基于原型的)
- 无类 (C):没有类的概念,通常不支持数据与方法的绑定写法,不支持继承等操作。 通常没有面向对象三大特性 (封装/继承/多态)。虽然强行用面向对象的方式写也没问题。但最多只能叫无类的面向对象。 强行写的话:由于数据和方法无绑定,通常根据文件和命名方式绑定。无权限控制,我习惯用
_
结尾表示私有方法。继承上用组合替代继承。 - 自定义类型类 (Go):Go的类不仅局限于Struct,自定义的类型通常都可以当作类来使用,都有面向对象的特性:可以继承任意类型、扩展类方法、实现接口
什么是对象?
(结合上一节一起看)
- 对象:这个不同语言定义的就不同了。我认为只要能有模板个创建多个有相同特征变量的,都能叫对象。当然,这不总是对的。最简单的就是“基本类型”到底算不算对象
- 类对象 / Class对象 (大多数语言,如C++、Java、C#):一般有Class关键字,支持类的继承,权限控制等。通过实例化Class类出来的东西才是类,而基本类型不是。对象是基于类的实例
- Struct对象:略
- 原型对象 (JavaScript):每个对象都有一个Prototype链,原型能继承,所有对象的共同根祖先是Object
- 皆对象 (JavaScript、Python、Ruby):所有东西,乃至 int / 函数 / 模块 都属于对象
- 无对象 (C)
什么是面向对象语言?
- 面向对象语言 / 类对象 (大多数语言,如C++、Java、C#)
- 完全面向对象 (Java):根部只有类定义,包括 main 函数要在任意一个自定义类里 (如果定义在多个类里,编译要指定,如
java ClassA
) - 支持面向对象 / 多范式编程语言 (大多数语言,C++、C#、Go):支持面向对象、面向过程、函数式、过程式。根部可以有类、函数、基本类型。 其中 Go 其实和 Java 有些类似的理念:Go 的资源全在包中,包括 main 函数要在 main 包中。
- 完全面向对象 (Java):根部只有类定义,包括 main 函数要在任意一个自定义类里 (如果定义在多个类里,编译要指定,如
- 基于原型语言 / 皆对象 / 原型对象 (JavaScript)
- 基于对象语言 / 皆对象 (Python、Ruby),也叫 object-based 语言
- 非 class "类" (Go、Rust)
- (Go):没有传统意义上的“类”概念,取而代之的是“类型”(Type)和“接口”(Interface)。
- 类型:结构体可以包含字段(Field)和方法(Method),方法可以与结构体关联。
- 接口:定义了一组方法签名。任何实现了这些方法的类型都可以被看作是该接口的实例。接口在Go中用于实现多态性,而不是通过继承实现
- (Rust):没有传统意义上的类和对象,但它提供了其他机制来实现类似面向对象编程的功能
- 结构体:Rust中的结构体类似于其他语言中的对象,可以包含字段和方法。
- 枚举:不仅可以表示一组值,还可以为不同的枚举值定义不同的方法
- 特质 (Trait):定义了一组方法签名,类似接口和多态性的功能
- (Go):没有传统意义上的“类”概念,取而代之的是“类型”(Type)和“接口”(Interface)。
- 面向过程编程语言 (如 C)
- 函数式编程语言 (如 Haskell、Erlang):更侧重于函数和不可变数据结构。计算是通过纯函数的应用来进行的,而不是通过对象的状态变化
- 逻辑编程语言 (如 Prolog):逻辑编程语言中的对象通常是指事实和规则,而不是传统意义上的对象。在Prolog中,程序是由一系列的事实和规则组成的,这些事实和规则可以被视为“对象”,它们通过逻辑运算来表达程序的逻辑。
面向对象编程
外壳类
- 用Java编写的所有代码都位于某个类的内部(包括main函数)
- 而C/C++、Python可以有代码在外面
对象的写法
C
:不是面向对象语言,没有类,但可用结构模拟举例:
struct inflatable {char name[20]; float volume;} inflatable guest = {'Ben', 1.1}
Python
举例:
class Dog(): # 定义 def __init__(self, name, age): # 构造函数 self.name = name self.age = age my_dog = Dog('willie', 6) # 使用 # 句点运算符 # 访问类成员/方法
C++
举例:
class Dog // 声明 { private: char name[50]; int age; public: Dog (char *, int); // 构造函数 } Dog::Dog(char * name1, int age1) // 实现 { name = name1; age = age1; } my_dog = Dog('willie', 6); // 使用 // 句点运算符 // 访问类成员/方法
Java
举例:
public class FirstSample { public static void main(String[] args) // 可以打psvm+tab来自动生成。公共类的main方法 { System.out.println("We will not use 'Hello, World!'"); } }
JavaScript
:js的对象概念有所不同:万物皆对象
区别概括
- 类的设计不同
Python
:需分离类文件、客户代码 在不需要分离的情况下,两者可写在一起C++
:需分离类的头文件、类的实现代码、客户代码 在不需要分离的情况下,三者可写在一起- 区别原理:
C++
不能像Python
那样合并类的头文件和实现代码- 一来:Python本身就不需要声明头文件 (如果只是为了查看用法,python的
dir()
和help()
方法更方便,而且help()
的第一行一般就是类似于原型的声明) - 二来:若是合并,则多个文件引用该类库时,会违反单一定义原则。而Python则没有单一定义的限制
- 一来:Python本身就不需要声明头文件 (如果只是为了查看用法,python的
- 构造函数不同
Python
:使用名为__init__
的函数作为构造函数C++、Java
:使用与类名同名的函数作为构造函数
- 类实例的引用
Python
(更直观)- 定义函数时:需要显示标注接受
self
变量 - 引用实例成员时:使用
self
和句点运算符 - 引用实例本身时:使用
self
- 调用函数时:不显示传递实例自身
- 定义函数时:需要显示标注接受
C++
- 定义函数时:不需要显示标注接受自身
- 引用实例成员时:无需借助
self
- 引用实例本身时:需要借助
this
指针 - 调用函数时:不显示传递实例自身,但可以通过后置类型来标明自身不被更改,如
Dog::fn(Dog dog) const
- 公有 or 私有
C
:结构成员默认值为公有Python
:类默认的成员方法和数据成员均公有C++
:类默认的成员方法和数据成员均私有
对象指针,java的对象实例本质是指针
不可错误地将Java的对象实例理解为C++的引用,而必须要看成C++的对象指针
性质上的区别
在C++中没有空引用,并且引用不能被赋值
Date birthday; // Java // 等同于 Date* birthday; // C++ // 不同于 Date& birthday; // C++,不可空引用、不可被赋值 // 不同于 Date birthday; // C++,表示的是值,传参时会传递整个对象
存储空间上的区别
所有的Java对象都存储在堆中。当一个对象包含另一个对象变量时,这个变量依然包含着指向另一个堆对象的指针。
如果使用一个没有初始化的指针,运行系统将会产生一个运行时错误,而不是生成一个随机的结果。同时,不必担心内存管理问题,垃圾收集器将会处理相关的事宜。
传参时的区别
- 不能编写一个交换两个雇员对象的方法,因为交换的只是拷贝进方法中的两个对象实例的地址,而并不能改变外部的两个对象实例的地址
this指针
- 在Java中,this引用等价于C++的this指针
三大特性
继承
包括是否允许多继承
特殊:Python甚至可以自己继承自己,我的父亲竟是我自己……奇奇怪怪
多态之运算符重载
运算符重载
- Java没有提供运算符重载功能。程序员无法重定义+和*运算符,使其应用于BigInteger类的add和multiply运算