part 8: comparison between OOL and FL

本文探讨了面向对象编程(OOP)与函数编程的主要区别,包括操作定义方式、多态处理、多重继承等方面,并深入讨论了双分派(Double Dispatch)、多重分派(Multiple Dispatch)等概念。
OOP和函数编程的区别
表格:行是operation,列是variant

函数编程:
     每个operation都是一个函数,每个函数都有若干branch,每个branch都对应一个variant
     定义datatype,每个variant都对应一个constructor
面向对象编程:
     定义一个基类,每个operation是一个类函数,基类中的函数是抽象的
     每个variant是一个子类,并且实现所有的抽象函数

问题一:如果有函数带有多种类型的参数?

函数编程:
    通过wildcard pattern + helper function + case语句
面向对象编程:
     Double Dispatch

Double Dispatch
将需要知道对方的类 转化成 调用对方的函数
第一次分配:variant类应该知道自己如何做一个operation=>如Int类型就应该调用arg.add_int(self)
第二次分配:对方的add_int知道应该如何将自己和int相加
调用栈:
     add(a, b)
     a.add_values(b)
     b.add_A的类型(a自己)
     b正确处理



Multiple Dispatch
每个add_values都有自己对应的参数类型,类里会有多个add_values
当调用a.add_values(b),将会在运行时挑选出A中接收B类型的参数的add_values, 直接调用
注意:Java和C++的static overloading虽然也能根据参数类型挑选对应函数,但是是编译期决定的,并不是运行时决定的。

多重继承:可能会在fields和methods上有冲突
     C++是支持多重继承的+abstract method
     Ruby运行有一个直接的基类和多个mixin
     Java支持一个直接的基类和实现多个接口

Mixin
类似接口,类能include mixin, 但是不能直接实例化mixin。
minxin不能有instancevariable
定义:module M … end
使用:class A < B
               include M
          end
Ruby自带的mixin: Enumerable(实现each方法)和Comparable(实现<=>方法)
     
Abstract method和high-order function的相同之处
     都可以先定义一个框架,由client实现其中的细节。
     Abstract method是通过override函数实现的
     High-order function是通过传入函数实现的

Polymorphism:
ML中:parametric polymorphism / generics
Ruby中:subtype polymorphism / subtyping
Generic和Subtyping:
     Generic适用于 可以是任何类型的参数,但必须是同一个类型 的情况
     Subtyping适用于 有extra fields的对象的代码重用 的情况
Bounded Polymorphism:
     Generic + Subtyping
     对于depth subtype如List,可以使用List<T extend A>,这样可以修改List的内容,替换成其他的T,但是注意,都是同类型的。

Subtyping:
     让一个类型{f1:t1, f2:t2...}也是类型{f2:t2…}。前者是subtype,subtype拥有更多的信息。
     t1 <: t2: t1是t2的subtype。
     如果e是t1,那么e也是t2。t2可以理解成父类,t1是子类,子类能拥有更多的field,且子类是基类
     任何使用t2的地方都可以使用t1(t1是t2,但是t2未必是t1)
     Depth subtyping:
          如果t1<:t2, 不能让 t3 : {f1:t1} <: t4 : {f1:t2} 
          原理:如果有函数将x.f1 = t2,那么就会造成t3.f1 = t2。但是如果通过t3.f1去取t1比t2多出来的fields就会报错。
                     当有赋值的时候,depth subtyping就会出现field丢失的情况
                     因此Java禁止赋值一个t1类型的数组内容为t2,但是允许depth subtyping
                     所有类型都可以看做是Null的subtype,所以Java中也会在运行时检查Null
      Function subtyping:不是如何调用函数,而是函数本身的委托
          如果 ta <: tb,则函数t->ta <: t->tb。能返回更多fields(promise more)的函数可以替换。return type: covariant(works the same way)
          如果 ta <: tb,则函数tb->t <: ta->t。需要更少fields(need less)的函数可以替换。argument type: contravariant(works the oposite way)
          除了self/this这个参数,由于实现问题必须是subtype,不能使contravariant的
     OOP中的subtype:
          因为field能够修改,所以subtype的field类型不能改变(原因参照depth subtyping)
          因为methods不能修改,所以subtype的methods能够使用supertype对应函数的subtype     
     Subclass和subtype不同:
          class:定义了对象的行为,子类通过继承并extend/override这些behavior
          type:定义了对象的类型和能够响应的消息,子类型是为了替换父类型并且防止发生错误。
<think> 我们正在讨论如何解决C语言中的'warning: comparison between pointer and integer'警告。根据引用[1][2][3],这个警告通常发生在将指针与整数值进行比较时。引用[3]指出,例如将`char`(被视为整数)与`NULL`(指针)比较会触发此警告。 解决方法: 1. 确保比较的两个操作数类型匹配。 2. 如果应该比较字符,则使用字符常量(例如`'\0'`)而不是`NULL`。 3. 如果应该比较指针,则确保两个操作数都是指针类型。 示例代码: 假设有代码: ```c char *str = "example"; if (str[0] == NULL) { // 这里str[0]是char,而NULL是指针 // ... } ``` 修正:如果意图是检查字符串的第一个字符是否为终止符,应该使用`'\0'`而不是`NULL`。 ```c if (str[0] == '\0') { // 正确:两个都是字符类型 // ... } ``` 另一个情况:可能混淆了指针和整数。 引用[2]提到:给指针变量赋值时,应该赋地址值。同样,比较时也要注意类型。 例如: ```c int *p; // ... 初始化p if (p == 10) { // 警告:比较指针和整数 // ... } ``` 修正:如果是要比较指针指向的值,应该先解引用: ```c if (*p == 10) { // 正确:比较两个整数 // ... } ``` 或者,如果是要比较指针本身的值(地址)是否等于某个特定地址,那么应该将整数强制转换为指针类型(但这种做法很少见,通常只在嵌入式系统中直接操作地址): ```c if (p == (int*)10) { // 正确:两个都是指针 // ... } ``` 总结步骤: 1. 识别触发警告的代码行。 2. 确定操作数的类型:一个是整数类型(如`char`, `int`等),另一个是指针(或反之)。 3. 根据意图修正: - 如果是要比较数值,确保两个操作数都是同一整数类型(注意:字符是整数类型)。 - 如果是要比较指针(地址),确保两个操作数都是指针类型。 4. 常见错误:用`NULL`(指针)来比较字符,应替换为`'\0'`(数值0)。 引用[3]中明确提到,将`argv[i][1]`(`char`类型)与`NULL`(指针)比较会导致警告,应改用`'\0'`。 因此,解决警告的关键在于理解操作数的类型并确保类型匹配。 下面我们生成相关问题: </think> ### 解决 'warning: comparison between pointer and integer' 警告的方法 在 C 语言中,`warning: comparison between pointer and integer` 警告通常发生在将**指针**与**整型**变量进行比较时。以下是详细解决方法和常见原因分析: #### 📌 核心原因分析 1. **类型不匹配**:指针(内存地址)与整型(数值)属于不同类型数据 2. **常见错误场景**: - 字符 `char` 与 `NULL` 比较:`char_var == NULL` - 指针与字面值比较:`ptr == 0`(0 既是整数又是空指针) - 混淆指针与指向的值:`*ptr == ptr` #### 🔧 解决方案与示例 ##### 1. 字符比较时使用字符常量替代 NULL ```c // 错误示例:comparison between pointer and integer if (argv[i][1] == NULL) // argv[i][1]是char,NULL是指针 // 正确修改:使用'\0'标识字符串结束 if (argv[i][1] == '\0') // 比较两个char类型[^3] ``` ##### 2. 指针比较时确保类型一致 ```c // 错误示例 int *ptr = ...; if (ptr == 10) // ptr是指针,10是整数 // 正确修改:将整数转换为指针类型 if (ptr == (int*)10) // 双方都是指针类型[^2] ``` ##### 3. 区分指针与指向的值 ```c // 错误示例 char buffer[10]; if (buffer == '\0') // buffer是数组指针,'\0'是字符 // 正确修改:解引用指针获取值 if (*buffer == '\0') // 比较字符值 ``` #### 🛠️ 调试技巧 1. **使用编译器提示**:`gcc -Wall -Wextra` 开启所有警告 2. **检查变量类型**: ```c printf("Type: %s\n", typeof(var)); // C11可用 ``` 3. **强制类型转换**:明确转换后再比较 ```c if ((intptr_t)ptr == 0x1000) // 整型指针转换 ``` #### 💡 预防措施 1. **使用标准宏**: ```c #include <stdint.h> if (ptr == NULL) // NULL明确表示为指针 ``` 2. **启用编译器严格模式**: ```bash gcc -Werror=pointer-integer-comp -o program source.c ``` 3. **静态代码分析工具**:使用 Clang-Tidy 或 PVS-Studio 提前发现问题 > **关键原则**:指针存储内存地址(通常 4/8 字节),整数存储数值(大小可变),二者二进制表示不同,直接比较可能导致未定义行为[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值