跳至主要內容

Different_对象和类

LincZero大约 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 包中。
  • 基于原型语言 /  皆对象 / 原型对象 (JavaScript)
  • 基于对象语言 /  皆对象 (Python、Ruby),也叫 object-based 语言
  • 非 class "类" (Go、Rust)
    • (Go):没有传统意义上的“类”概念,取而代之的是“类型”(Type)和“接口”(Interface)。
      • 类型:结构体可以包含字段(Field)和方法(Method),方法可以与结构体关联。
      • 接口:定义了一组方法签名。任何实现了这些方法的类型都可以被看作是该接口的实例。接口在Go中用于实现多态性,而不是通过继承实现
    • (Rust):没有传统意义上的类和对象,但它提供了其他机制来实现类似面向对象编程的功能
      • 结构体:Rust中的结构体类似于其他语言中的对象,可以包含字段和方法。
      • 枚举:不仅可以表示一组值,还可以为不同的枚举值定义不同的方法
      • 特质 (Trait):定义了一组方法签名,类似接口和多态性的功能
  • 面向过程编程语言 (如 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:使用名为__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运算