C语言 编写面向对象的代码

C语言本身不是像C++或Java这样的面向对象语言,但通过使用结构体、函数指针等技巧,可以在C中模拟面向对象编程(OOP)概念。本文主要介绍C语言中模拟类、方法以及继承等OOP概念。

1、使用结构体模拟类

C语言中,可以使用struct(结构体)来模拟类,结构体可以包含类似类中属性的数据成员。

#include <stdio.h>

// 定义一个结构体来模拟类
typedef struct {
    int x, y;
} Point;

// 创建一个新Point的函数(构造函数)
Point create_point(int x, int y) {
    Point p = {x, y};
    return p;
}

// 打印Point的函数(方法)
void print_point(Point p) {
    printf("Point(%d, %d)\n", p.x, p.y);
}

2、使用函数指针模拟方法

通过使用函数指针,可以在C语言中模拟面向对象的“方法”,即将行为(函数)与特定实例的结构体关联。

#include <stdio.h>

typedef struct {
    int x, y;
    void (*print)(struct Point);  // 函数指针作为"方法"
} Point;

void print_point(Point p) {
    printf("Point(%d, %d)\n", p.x, p.y);
}

Point create_point(int x, int y) {
    Point p = {x, y, print_point};  // 初始化时赋值函数指针
    return p;
}

int main() {
    Point p = create_point(3, 4);
    p.print(p);  // 通过函数指针调用方法
    return 0;
}

3、 模拟继承

C语言没有直接支持继承,但可以通过将一个结构体嵌套在另一个结构体中,模拟继承的行为。

#include <stdio.h>

// 基类
typedef struct {
    int x, y;
} Shape;

// 派生类(继承自Shape)
typedef struct {
    Shape base;  // 通过包含基类结构体实现“继承”
    int radius;
} Circle;

// 打印Shape的函数
void print_shape(Shape s) {
    printf("Shape at (%d, %d)\n", s.x, s.y);
}

// 打印Circle的函数
void print_circle(Circle c) {
    printf("Circle at (%d, %d) with radius %d\n", c.base.x, c.base.y, c.radius);
}

int main() {
    Shape s = {10, 20};
    print_shape(s);  // 打印基类

    Circle c = {{30, 40}, 5};  // 初始化Circle,包含Shape部分
    print_circle(c);  // 打印派生类
    return 0;
}

4、模拟多态

OOP中的多态允许你使用单一的接口来表示不同类型的对象。在C语言中,可以通过函数指针来模拟多态行为,在不同的结构体类型上定义不同的行为。

#include <stdio.h>

// 定义基类,包含虚函数(函数指针)
typedef struct {
    void (*draw)(void *self);
} Shape;

void draw_shape(void *self) {
    printf("Drawing a generic shape\n");
}

// 定义派生类(Circle)并实现自己的draw方法
typedef struct {
    Shape base;  // 继承自Shape
    int radius;
} Circle;

void draw_circle(void *self) {
    Circle *circle = (Circle *)self;
    printf("Drawing a circle with radius %d\n", circle->radius);
}

int main() {
    Shape shape = {draw_shape};
    Circle circle = {{draw_circle}, 10};  // 用派生的draw方法初始化

    shape.draw(&shape);     // 调用基类的draw方法
    circle.base.draw(&circle);  // 通过多态调用派生类的draw方法
    return 0;
}

5、封装

C中,可以通过使用static函数和变量来模拟封装,限制对结构体内部成员的访问(类似于面向对象语言中的私有字段)。

#include <stdio.h>

typedef struct {
    int x, y;
} Point;

// 私有函数(不能在文件外部访问)
static void set_coordinates(Point *p, int x, int y) {
    p->x = x;
    p->y = y;
}

void print_point(Point p) {
    printf("Point(%d, %d)\n", p.x, p.y);
}

int main() {
    Point p;
    set_coordinates(&p, 5, 10);  // 只能在当前文件内访问
    print_point(p);
    return 0;
}

6、构造函数和析构函数

C语言没有内建的构造函数和析构函数,但可以通过使用初始化和清理函数来模拟这些行为。

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int x, y;
} Point;

Point *create_point(int x, int y) {
    Point *p = malloc(sizeof(Point));
    p->x = x;
    p->y = y;
    return p;
}

void destroy_point(Point *p) {
    free(p);
}

int main() {
    Point *p = create_point(5, 10);  // 构造函数
    printf("Point(%d, %d)\n", p->x, p->y);
    destroy_point(p);  // 析构函数
    return 0;
}

推荐阅读
cjavapy编程之路首页