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应用绑定。。真是不行不行的了。。
另外关于多态的实现,其实我早就想用函数指针了,写基类的时候写写删删了好几次。。。无奈还是没写。