C中的OOP,隐式传递self作为参数
我一直在编写一个示例来学习C中的OOP。目前,我已经编写了这段代码,这段代码正在运行,但是我对使这些方法隐式地将self作为参数传递很感兴趣C中的OOP,隐式传递self作为参数,c,oop,C,Oop,我一直在编写一个示例来学习C中的OOP。目前,我已经编写了这段代码,这段代码正在运行,但是我对使这些方法隐式地将self作为参数传递很感兴趣 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> //#include "Stopwatch.h" typedef struct stopwatch_s { unsigned int milliseconds; unsigned i
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
//#include "Stopwatch.h"
typedef struct stopwatch_s
{
unsigned int milliseconds;
unsigned int seconds;
unsigned int minutes;
unsigned int hours;
bool is_enabled;
void ( *tick ) ( struct stopwatch_s* );
void ( *start ) ( struct stopwatch_s* );
void ( *stop ) ( struct stopwatch_s* );
void ( *reset ) ( struct stopwatch_s* );
} stopwatch_t;
static void tick (stopwatch_t* _self)
{
stopwatch_t * self = _self;
if (self->is_enabled)
{
self->milliseconds++;
if (self->milliseconds >= 1000)
{
self->milliseconds = 0;
self->seconds++;
if (self->seconds >= 60)
{
self->seconds = 0;
self->minutes++;
if (self->minutes >= 60)
{
self->minutes = 0;
self->hours++;
}
}
}
}
}
static void start (stopwatch_t* _self)
{
stopwatch_t * self = _self;
self->is_enabled = true;
}
static void stop (stopwatch_t* _self)
{
stopwatch_t * self = _self;
self->is_enabled = false;
}
static void reset (stopwatch_t* _self)
{
stopwatch_t * self = _self;
self->is_enabled = false;
self->milliseconds = 0;
self->seconds = 0;
self->minutes = 0;
self->hours = 0;
}
void * new_stopwatch()
{
stopwatch_t * newInstance = (stopwatch_t *)calloc(1, sizeof(stopwatch_t));
newInstance->is_enabled = false;
newInstance->milliseconds = 0;
newInstance->seconds = 0;
newInstance->minutes = 0;
newInstance->hours = 0;
newInstance->tick = &tick;
newInstance->start = &start;
newInstance->stop = &stop;
newInstance->reset = &reset;
return newInstance;
}
void main()
{
struct stopwatch_s * Stopwatch = new_stopwatch();
printf ("Initial: %d\n", Stopwatch->milliseconds);
Stopwatch->start (Stopwatch);
Stopwatch->tick (Stopwatch);
Stopwatch->tick (Stopwatch);
Stopwatch->tick (Stopwatch);
printf ("Started: %d\n", Stopwatch->milliseconds);
Stopwatch->stop (Stopwatch);
Stopwatch->tick (Stopwatch);
printf ("Stopped: %d\n", Stopwatch->milliseconds);
Stopwatch->reset (Stopwatch);
printf ("Reset: %d\n", Stopwatch->milliseconds);
}
我会写字
Stopwatch->tick();
这是SimPy,不是C语言的特征,这可能是发明C++的动机之一,所以单独使用C,这是不可能的。 C语言中有很多库,我所知道的基本上都使用与您相同的方法,使用结构来存储状态(在您的例子中,
stopwatch\t
),但只要尽可能跳过结构中的函数指针即可;这不是因为C程序员不喜欢OOP,而是因为OOP的冗余度较低
stoplib_tick(Stopwatch);
而不是
Stopwatch->tick(Stopwatch);
Stopwatch->tick(Stopwatch);
另外,在结构的每个实例中携带一堆始终相同的函数指针是个坏主意;这只是浪费空间,而且可能导致错误。如果需要,可以创建一个包含类型的所有函数指针的结构,并从该表中调用它们。基本上,C++中的VTables就是这样。
因此,没有C程序员会这样做;除非您的函数指针实际上可能会发生更改,否则您不能将可以对结构执行的操作保留在该结构中
我不知道你指的那本书,但如果它鼓吹这样做,我不喜欢它
严重的,如果你想要C对象定位,去C++;除了编码几个内核之外,你可以用C++做的事情很少,C可以用C来实现。不要像20世纪60年代那样
EDIT开始阅读你链接到的PDF——说真的,现在谁会使用ANSI-C特别是如果你想舒适地使用结构等,你不应该使用比C99更旧的东西(考虑到它已经很旧了…),因此,这本书已经过时了,除非你提出了一个非常重要和传统的系统(“嗨,我从20世纪80年代就开始研究核武器控制系统,我需要修复这个和那个”),我想说,我想不出有什么情况下遵循这些例子是有意义的;显然,“我正在从头开始学习用C语言进行OOP”不应该基于已经过时十多年的东西
编辑:您可以发表评论
因为我来自一个嵌入式环境,坚持ANSI-C,一切都会正常工作 我有点勉强同意。有些平台上缺乏C99支持,但是:大多数编译器支持C99的绝大多数功能。ANSI-C(应该更准确地称为C89,因为C99也是ANSI标准)现在已经超过25岁了,在不知道的情况下,你的代码甚至可能不符合C89。书中的代码肯定不是有效的ANSI-C,不管作者怎么说。例如,ANSI-C没有
/
注释;这只是一个小错误,我猜所有的编译器,除非设置为pedantic m奥德不会抱怨,但这仍然不是一个好的景象
所以:帮你自己一个忙,不要依赖一本选择性地使用难用语言状态的书,而试着使用编译器支持的任何东西
另外:我越是读那本书,在(现代)OOP中的一个好练习就越少(第3页,PDF第9页):
通用指针void*
贯穿始终。一方面,它使
不可能发现一个集合是什么样子的,但另一方面它允许我们
将几乎所有内容传递给add()
和其他函数
是的,因为类型安全性对C语言的成功不是一个至关重要的概念,而且因为传递void*
然后,在方法的第一行,将其转换为所需的指针类型是一个好主意。啊!如果你想要可怕的bug,那就是得到它们的方法
看看像CPython这样的东西:Python是一种OO语言,但是解释器/编译器是用C编写的。Python使用PyObject结构进行C-OOP,作为主要功能,PyObject结构有一个类型引用,以避免执行这些盲转换。您不应该能够传递const char[]
在这里,您希望有一个指向某个对象的指针,多态性的全部要点是,您可以使用类型的子类型,但不能完全不同的类型,并使用函数。这本书对OOP没有任何好处。请阅读其他内容。我很确定有关于CPython设计的书籍,我个人认为再糟糕不过了
我不知道如何构造我的“对象”,所以
Stopwatch->tick(秒表);
我可以写Stopwatch->tick();
<>这在标准C中是不可能的。你需要把接收方作为一个显式形式的参数传递给C函数(与C++相比,它有<代码>这个< /C> >作为隐式形式)。
然而:
- 通常,您希望将所有方法函数打包到一个包含多个函数成员的
结构中(并使每个实例以指向该
结构的指针开始)。请阅读-s
- 您可以使用一些宏(或者内联函数)来避免给出两次
;您仍然可以编写Stopwatch
而不是TICK(Stopwatch)
;的扩展可能很有用Stopwatch->TICK();
send
函数(这样你就可以编码send(秒表,滴答声)
而不是你梦寐以求的StopWatch->TICK()
)或宏
typedef struct stopwatch_t stopwatch_t; // incomplete type
stopwatch_t* sw_new (void); // "constructor"
void sw_delete (stopwatch_t* sw); // "destructor"
void sw_tick (const stopwatch_t* sw); // public member function
// any number of public functions here
// mind const correctness!
struct stopwatch_t // implementation
{
// true private variables:
unsigned int milliseconds;
unsigned int seconds;
unsigned int minutes;
unsigned int hours;
bool is_enabled;
};
stopwatch_t* sw_new (void)
{
// same as what you already have
}
// the module is responsible for cleaning up its own mess, NOT THE CALLER
void sw_delete (stopwatch_t* sw)
{
free(sw);
}
// any number of public member functions:
void sw_tick (const stopwatch_t* sw)
{
// here sw is the "self"/"this" pointer
}
// any number of private member functions:
static void sw_do_stuff (stopwatch_t* sw)
{
}
// stop_watch.h
typedef struct stop_swatch_ stop_watch;
stop_watch* stop_watch_create();
stop_watch* stop_watch_clone(stop_watch const* sw);
void stop_watch_dispose(stop_watch* sw);
void stop_watch_tick(stop_watch* sw);
void stop_watch_start(stop_watch* sw);
void stop_watch_stop(stop_watch* sw);
void stop_watch_reset(stop_watch* sw);
// stop_watch.h
typedef struct stop_watch_functions_ stop_watch_functions;
typedef struct {
stop_watch_functions const* functions;
} stop_watch;
struct stop_watch_functions_ {
void (*clone)(stop_watch const*);
void (*dispose)(stop_watch*);
void (*tick)(stop_watch*);
void (*start)(stop_watch*);
void (*stop)(stop_watch*);
void (*reset)(stop_watch*);
};
stop_watch* stop_watch_clone(stop_watch const* sw);
void stop_watch_dispose(stop_watch* sw);
void stop_watch_tick(stop_watch* sw);
void stop_watch_start(stop_watch* sw);
void stop_watch_stop(stop_watch* sw);
void stop_watch_reset(stop_watch* sw);
// stop_watch.c
stop_watch* stop_watch_clone(stop_watch const* sw) {
return (*sw->functions->clone)(sw);
}
void stop_watch_dispose(stop_watch* sw) {
return (*sw->functions->dispose)(sw);
}
void stop_watch_tick(stop_watch* sw) {
return (*sw->functions->tick)(sw);
}
void stop_watch_start(stop_watch* sw) {
return (*sw->functions->start)(sw);
}
void stop_watch_stop(stop_watch* sw) {
return (*sw->functions->stop)(sw);
}
void stop_watch_reset(stop_watch* sw) {
return (*sw->functions->reset)(sw);
}
// my_stop_watch.h
#include "stop_watch.h"
typedef struct my_stop_watch_ my_stop_watch;
my_stop_watch* my_stop_watch_create();
stop_watch* my_stop_watch_upcast(my_stop_watch* msw);
my_stop_watch* my_stop_watch_downcast(stop_watch* sw);
// my_stop_watch.c
#include "my_stop_watch.h"
struct my_stop_watch_ {
stop_watch base;
unsigned int milliseconds;
unsigned int seconds;
unsigned int minutes;
unsigned int hours;
bool is_enabled;
};
static stop_watch* my_stop_watch_clone(stop_watch const* sw) {
my_stop_watch* new = malloc(sizeof(my_stop_watch));
memset(new, (my_stop_watch const*)sw, sizeof(my_stop_watch));
}
static void my_stop_watch_dispose(stop_watch* sw) {
free(sw);
}
static void my_stop_watch_tick(stop_watch* sw) {
my_stop_watch* msw = (my_stop_watch*)sw;
/* do something */
}
static void my_stop_watch_start(stop_watch* sw) {
my_stop_watch* msw = (my_stop_watch*)sw;
/* do something */
}
static void my_stop_watch_stop(stop_watch* sw) {
my_stop_watch* msw = (my_stop_watch*)sw;
/* do something */
}
static void my_stop_watch_reset(stop_watch* sw) {
my_stop_watch* msw = (my_stop_watch*)sw;
/* do something */
}
static stop_watch_functions const my_stop_watch_table = {
&my_stop_watch_clone,
&my_stop_watch_dispose,
&my_stop_watch_tick,
&my_stop_watch_start,
&my_stop_watch_stop,
&my_stop_watch_reset
};
my_stop_watch* my_stop_watch_create() {
my_stop_watch* msw = malloc(sizeof(my_stop_watch*));
msw->base = &my_stop_watch_table;
/* do something */
return msw;
}
stop_watch* my_stop_watch_upcast(my_stop_watch* msw) {
return &msw->base;
}
my_stop_watch* my_stop_watch_downcast(stop_watch* sw) {
if (sw->functions != &my_stop_watch_table) {
return NULL;
}
return (my_stop_watch*)((char*)sw - offsetof(my_stop_watch, base));
}