Introduction
唉。。这个题本来是我给本校一门C++的课出的期末考试题,无奈被批”平常老嘱咐不要写C风格的程序”,然后就被干掉了。。但是这个技能本身还是有一定意义的,在此我就直接把原题目的空都填好了分享给大家。
注:下面这堆中,声明都是真的,实现都是我口胡的。最近口胡能力越来越强了。。。
题目描述
Pebble是一款于2013年初上市的智能手表,具有一块类似Kindle的黑白电子墨水屏,支持蓝牙链接以便从手机获取消息通知。
相对于今天才上市的Apple Watch,Pebble更加开放和友好的开发环境赢得了广大Geek的青睐。
虽说开发环境比较友好,但是,并!没!有!C++编译器,基本的开发语言只有C。。。
但是,这并不妨碍你使用C来开发一个简单的Pebble程序,通过本学期的学习,你已经掌握了C语言的很多语法。
|C和C++共同的语法部分(本题中可以使用)|C语言不具备的语法(本题中无法使用的)|
|基本的数据类型|class,namespace,template|
|数组及指针|struct中无法包含函数体|
|循环体及函数体|string数据类型|
|宏语句|new与delete语句|
并且,即便没有class,也并不妨碍你使用面向对象的思想来开发程序。
我们现在就来尝试使用C来模拟出一个类,由于没有class,我们只能先用struct来构建出他的数据部分:
我们现在就来尝试使用C来模拟出一个类,由于没有class,我们只能先用struct来构建出他的数据部分:
1 2 3
| struct GPoint { unsigned int x,y; };
|
接下来我们可以用下面的语句来定义GPoint类型的对象了
为了调用方便,不如就用typedef把它改造的更像类一些
1
| typedef struct GPoint GPoint;
|
现在我们就可以摆脱那个struct啦
下面这个宏给我们演示了如何模拟出一个构造函数
利用{}来构建一个结构对,接下来强制类型转换成GPoint类型并返回
1
| #define GPoint(x, y) ((GPoint){(x), (y)})
|
调用就像这样
上面的struct和typedef两句还可以合并起来写
1 2 3 4
| typedef struct GSize { unsigned int w,h; } GSize; #define GSize(w, h) ((GSize){(w), (h)})
|
接下来我们来构造一个内嵌其他类型的类
1 2 3 4
| typedef struct GRect { GPoint origin; GSize size; } GRect;
|
现在我们来仿写一个GRect类型的构造函数
1
| #define GRect(x, y, w, h) ((GRect) { {(x), (y) }, {(w), (h)}})
|
对于简单的,不含函数的类,我们用上面的办法就可以解决了。
对于一些更基本的类,甚至可以这样
1 2 3
| typedef enum GColor { GColorClear,GColorBlack } GColor;
|
接下来我们来用C来构建一个复杂的基类
1 2 3 4 5 6 7
| typedef struct Layer Layer; struct Layer { Layer* this; GRect bounds; };
|
现在我们来实现这个类的构造函数
1 2 3 4 5 6
| Layer* layer_create(GRect bounds) { Layer layer; Layer* this=&layer; this->bounds=bounds; return this; }
|
同样还要有析构函数
1 2 3
| void layer_destroy(Layer* this) { free(this); }
|
接下来定义一个成员函数,开头附加类名来表示这个类的归属
1 2 3
| GRect layer_get_bounds(Layer* this) { return this->bounds; }
|
以及其他成员函数,他们都以类名开头,第一个参数是这个类的对像的指针。对于一个静态函数,可以这样。
1
| void layer_add_child(Layer *parent, Layer *child);
|
接下来我们来模拟继承自Layer和Text两个类的子类TextLayer
1 2 3 4 5 6
| typedef struct TextLayer TextLayer; struct TextLayer { Layer* layer; TextLayer* this; };
|
接下来我们来实现子类的构造函数
1 2 3 4 5 6
| TextLayer* text_layer_create(GRect bounds) { TextLayer textLayer; TextLayer* this= &textLayer; this->layer=layer_create(bounds); return this; }
|
以及析构函数
1 2 3 4
| void text_layer_destroy(TextLayer* this) { layer_destroy(this->layer); free(this); }
|
以及一些成员函数
1 2 3 4 5 6 7
| Layer* text_layer_get_layer(TextLayer* this) { return this->layer; } void text_layer_set_text(TextLayer* text_layer, const char* text); const char* text_layer_get_text(TextLayer* text_layer); void text_layer_set_background_color(TextLayer* text_layer, GColor color); void text_layer_set_text_color(TextLayer* text_layer, GColor color);
|
以及其他成员函数
同样我们还有另一个继承自Layer的类,用来存储图片
1 2 3 4 5 6
| typedef struct BitmapLayer BitmapLayer; struct BitmapLayer { Layer* layer; BitmapLayer* this; };
|
现在我们还有一个同时继承自TextLayer和BitmapLayer的类
1 2 3 4 5 6
| typedef struct TextBitmapLayer TextBitmapLayer; struct TextBitmapLayer { TextLayer* textLayer; BitmapLayer* bitmapLayer; };
|
我们来仿照C++解决类似情况的手法实现这个类的构造函数
1 2 3 4 5 6 7 8 9 10
| TextBitmapLayer* text_bitmap_layer_create(GRect bounds) { TextBitmapLayer textBitmapLayer; TextBitmapLayer* this=&textBitmapLayer; this->textLayer=text_layer_create(bounds); BitmapLayer bitmapLayer; this->bitmapLayer=&bitmapLayer; this->bitmapLayer->this=&bitmapLayer; this->bitmapLayer->layer=this->textLayer->layer; return this; }
|
以及析构函数
1 2 3 4 5
| void text_bitmap_layer_detroy(TextBitmapLayer* this) { text_layer_destroy(this->textLayer); free(this->bitmapLayer); free(this); }
|
现在我们就来为pebble实现一个右图中那个简单的watchface吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| #include <pebble.h> static Window* s_main_window; static TextLayer* s_time_layer; static void update_time() { static void tick_handler(struct tm* tick_time, TimeUnits units_changed) { time_t temp = time(NULL); struct tm* tick_time = localtime(&temp); static char s_buffer[8]; strftime(s_buffer, sizeof(s_buffer), "%H:%M", tick_time); text_layer_set_text(s_time_layer, s_buffer); } static void main_window_load(Window* window) { Layer* window_layer = window_get_root_layer(window); GRect bounds = layer_get_bounds(window_layer); s_time_layer = text_layer_create(GRect(0, 52, bounds.size.w, 50)); text_layer_set_background_color(s_time_layer, GColorClear); text_layer_set_text_color(s_time_layer, GColorBlack); text_layer_set_font(s_time_layer, FONT_KEY_BITHAM_42_BOLD); text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter); layer_add_child(window_layer, text_layer_get_layer(s_time_layer)); } static void main_window_unload(Window* window) { text_layer_destroy(s_time_layer); } static void init() { s_main_window = window_create(); window_set_window_handlers(s_main_window, (WindowHandlers) { .load = main_window_load, .unload = main_window_unload }); window_stack_push(s_main_window, true); tick_timer_service_subscribe(MINUTE_UNIT, tick_handler); } int main(void) { init(); app_event_loop(); window_destroy(s_main_window); }
|
编译,运行!但是发现这个watchface显示的时间有时候会与真实时间有误差,请问误差最大是多少?为了降低误差,有什么办法吗?
最大偏差一分钟,因为每一分钟才调用一次tick_handler。把MINUTE_UNIT改成SECOND_UNIT就好了。
点评
我是忍住了才没喷AppleWatch…完全不可用的待机,不防水,必须和ios应用绑定。。真是不行不行的了。。
另外关于多态的实现,其实我早就想用函数指针了,写基类的时候写写删删了好几次。。。无奈还是没写。