携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
C++的面向对象
面向对象,都很熟悉
张口就出的, 封装、继承、多态
封装
即把数据和相应数据对应的操作给他们封存起来
使其形成一个类型
class Base {
protected:
int data;
public:
void print() { printf("[base]%d\n", data); }
void read(int data) { this->data = data; }
};
继承
可以把众多相似的类型中共同的部分给他抽象出来。
一个类只要继承了这个类,就拥有了这个类的东西
class Base {
protected:
int data;
public:
void print() { printf("[base]%d\n", data); }
void read(int data) { this->data = data; }
};
class Foo : public Base {
public:
void add() {}
void del() {}
};
多态
由子类去继承自父类,且对于相同的行为,表现出不同的特征 体现在子类重写父类的方法
class Base {
protected:
int data;
public:
virtual void print() { printf("[base]%d\n", data); }
void read(int data) { this->data = data; }
};
class Foo : public Base {
public:
void print() { printf("[Foo]%d\n", data); }
};
class Bar : public Base {
public:
void print() { printf("[Bar]%d\n", data); }
};
其实面向对象是一种思想,那么我C语言是不是也可以有对象呢?
那么,其实前人早已在用面向对象的思想干活了
没有这些语法糖,我们也可以活得很滋润
C语言的对象
封装
把相关数据封装到 struct 里面
用相关函数来进行操作
typedef struct {
int data;
} Base;
void Base_init(Base *const self, int x) { self->data = x; }
void Base_print(Base *const self) { printf("[base]%d\n", self->data); }
void Base_read(Base *const self, int x) { self->data = x; }
什么? 这样很麻烦? 可以,有解决办法的
struct Base_func;
typedef struct Base {
int data;
struct Base_func *func;
} Base;
void Base_print(Base *const self) { printf("[base]%d\n", self->data); }
void Base_read(Base *const self, int x) { self->data = x; }
struct Base_func {
void (*print)(Base *const);
void (*read)(Base *const, int);
};
void Base_init(Base *const self, int x) {
static struct Base_func baseFunc = { .print = Base_print, .read = Base_read };
self->data = x;
self->func = &baseFunc;
}
int main() {
Base base;
Base_init(&base, 1);
base.func->print(&base);
return 0;
}
这样,你就可以把函数封装起来然后调用,不过这一种有点不如第一种形式
继承
继承的本意是什么?把父类的东西全部拿过来用 那我们就可以写成这样
typedef struct {
int data;
} Base;
typedef struct {
Base base;
int foo;
} Foo;
void Base_init(Base *const self, int data) { self->data = data; }
void Base_print(Base *const self) { printf("[base]%d\n", self->data); }
void Base_read(Base *const self, int data) { self->data = data; }
void Foo_init(Foo *const self, int foo, int data) {
Base_init(&self->base, data);
self->foo = foo;
}
void Foo_print(Foo *const self) { Base_print(&self->base); }
void Foo_read(Foo *const self, int data) { Base_read(&self->base, data); }
可以看到,我的处理方式是调用foo类的init的时候,同时去初始化base的成员。
这就是谁的成员交给谁的构造
子类继承的父类的方法,这个时候就是直接调用父类的方法即可 然后子类再根据自身的特点,即可以实现子类的特化
多态
如何表现出动态多态的特性?
比如c++的用虚函数实现的动态绑定的实现?
在c语言中一个如何实现它呢?
这个时候就要用到前面提到的那种函数指针了
已经尽量少写代码了,但还是比较多
基类是Base
两个派生类是Foo 和 Bar
typedef struct {
struct Base_func *func;
int data;
} Base;
struct Base_func {
void (*print)(void *const);
};
void Base_print(void *const self) {
Base *This = (Base *)self;
printf("[base]%d\n", This->data);
}
void Base_read(Base *const self, int data) { self->data = data; }
void Base_init(Base *const self, int data) {
self->data = data;
self->func = (struct Base_func *)malloc(sizeof(struct Base_func));
*(self->func) = (struct Base_func){.print = Base_print};
}
typedef struct {
Base base;
int foo;
} Foo;
void Foo_print(void *const self) {
Foo *This = (Foo *)self;
printf("[foo]%d\n", This->foo);
}
void Foo_read(Foo *const self, int data) { Base_read(&self->base, data); }
void Foo_init(Foo *const self, int foo, int data) {
Base_init(&self->base, data);
self->foo = foo;
self->base.func->print = Foo_print;
}
typedef struct {
Base base;
double bar;
} Bar;
void Bar_print(void *const self) {
Bar *This = (Bar *)self;
printf("[bar]%lf\n", This->bar);
}
void Bar_read(Bar *const self, int data) { Base_read(&self->base, data); }
void Bar_init(Bar *const self, double bar, int data) {
Base_init(&self->base, data);
self->bar = bar;
self->base.func->print = Bar_print;
}
#define New(classname) (classname *)malloc(sizeof(classname))
void print(Base *base) { base->func->print(base); }
int main() {
Base *base = New(Base);
Base_init(base, 1);
print(base);
base = (Base *)New(Foo);
Foo_init((Foo *)base, 1, 2);
print(base);
base = (Base *)New(Bar);
Bar_init((Bar *)base, 1, 2);
print(base);
return 0;
}
总结
面向对象可以不需要语言支持,也大概可以磕磕碰碰的写出来
可是,我们可以发现,就是简单是一点点代码,c语言也会写很多出来,且容易出现不安全和未定义的情况
在用c语言时,语言假设我们知道自己在干什么,事实上可能是高看了我们
(还是C++、Java这种有面向对象语言支持的写了快,且不容易错误)