From f2a6d3aa738a73ab26eca7419846e778a8c5e1d0 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 8 Jan 2014 20:32:05 +0800 Subject: [PATCH] gb2312 to utf8, add md file --- demo/Animal/animal.c | 44 +- demo/Animal/animal.h | 30 +- demo/Animal/lw_oopc.c | 146 ---- demo/Animal/lw_oopc.h | 22 +- demo/Animal/main.c | 36 +- demo/Expr/expr.c | 62 +- demo/Expr/expr.h | 62 +- demo/Expr/lw_oopc.c | 14 +- demo/Expr/lw_oopc.h | 22 +- demo/Expr/main.c | 2 +- demo/expr-advance/expr.c | 72 +- demo/expr-advance/expr.h | 68 +- demo/expr-advance/lw_oopc.c | 14 +- demo/expr-advance/lw_oopc.h | 20 +- demo/expr-advance/main.c | 2 +- demo/expr-advance/memory_detector_result.txt | 5 - doc/轻量级的面向对象C语言编程框架介绍.doc | Bin 184832 -> 140800 bytes doc/轻量级的面向对象C语言编程框架介绍.md | 679 +++++++++++++++++++ lw_oopc.c | 14 +- lw_oopc.h | 22 +- 20 files changed, 928 insertions(+), 408 deletions(-) delete mode 100644 demo/Animal/lw_oopc.c delete mode 100644 demo/expr-advance/memory_detector_result.txt create mode 100644 doc/轻量级的面向对象C语言编程框架介绍.md diff --git a/demo/Animal/animal.c b/demo/Animal/animal.c index 0876d78..c042c02 100755 --- a/demo/Animal/animal.c +++ b/demo/Animal/animal.c @@ -1,24 +1,24 @@ -#include +#include #include #include "animal.h" -/* ödz */ +/* 设置动物的昵称 */ void Animal_setName(Animal* t, const char* name) { - // ٶnameС128ַΪʾ룬ƷвҪд + // 这里假定name小于128个字符,为简化示例代码,不做保护(产品代码中不要这样写) strcpy(t->name, name); } -/* ö */ +/* 设置动物的年龄 */ void Animal_setAge(Animal* t, int age) { t->age = age; } -/* Ǵк */ +/* 动物和我们打招呼 */ void Animal_sayHello(Animal* t) { - printf("Hello! %s%d! \n", t->name, t->age); + printf("Hello! 我是%s,今年%d岁了! \n", t->name, t->age); } -/* ʼdzƺ */ +/* 初始化动物的昵称和年龄 */ void Animal_init(Animal* t, const char* name, int age) { t->setName(t, name); @@ -32,22 +32,22 @@ FUNCTION_SETTING(sayHello, Animal_sayHello); FUNCTION_SETTING(init, Animal_init); END_ABS_CTOR -/* ijΪ */ +/* 鱼的吃行为 */ void Fish_eat(Animal* t) { - printf("ˮ! \n"); + printf("鱼吃水草! \n"); } -/* ĺΪ */ +/* 鱼的呼吸行为 */ void Fish_breathe(Animal* t) { - printf("! \n"); + printf("鱼用鳃呼吸! \n"); } -/* ƶΪ */ +/* 鱼的移动行为 */ void Fish_move(IMoveable* t) { - printf("ˮ! \n"); + printf("鱼在水里游! \n"); } -/* ʼdzƺ */ +/* 初始化鱼的昵称和年龄 */ void Fish_init(Fish* t, const char* name, int age) { Animal* animal = SUPER_PTR(t, Animal); @@ -63,22 +63,22 @@ FUNCTION_SETTING(IMoveable.move, Fish_move); FUNCTION_SETTING(init, Fish_init); END_CTOR -/* ijΪ */ +/* 狗的吃行为 */ void Dog_eat(Animal* t) { - printf("Թͷ! \n"); + printf("狗吃骨头! \n"); } -/* ĺΪ */ +/* 狗的呼吸行为 */ void Dog_breathe(Animal* t) { - printf("÷κ! \n"); + printf("狗用肺呼吸! \n"); } -/* ƶΪ */ +/* 狗的移动行为 */ void Dog_move(IMoveable* t) { - printf("ڵ! \n"); + printf("狗在地上跑! \n"); } -/* ʼdzƺ */ +/* 初始化狗的昵称和年龄 */ void Dog_init(Dog* t, const char* name, int age) { Animal* animal = SUPER_PTR(t, Animal); @@ -96,7 +96,7 @@ END_CTOR void Car_move(IMoveable* t) { - printf("ڿ! \n"); + printf("汽车在开动! \n"); } CTOR(Car) diff --git a/demo/Animal/animal.h b/demo/Animal/animal.h index af5ab2a..f8d5e22 100755 --- a/demo/Animal/animal.h +++ b/demo/Animal/animal.h @@ -1,38 +1,38 @@ -#ifndef ANIMAL_H_INCLUDED_ +#ifndef ANIMAL_H_INCLUDED_ #define ANIMAL_H_INCLUDED_ #include "lw_oopc.h" INTERFACE(IMoveable) { - void (*move)(IMoveable* t); // MoveΪ + void (*move)(IMoveable* t); // Move行为 }; ABS_CLASS(Animal) { - char name[128]; // dz(С128ַ) - int age; // + char name[128]; // 动物的昵称(假设小于128个字符) + int age; // 动物的年龄 - void (*setName)(Animal* t, const char* name); // ödz - void (*setAge)(Animal* t, int age); // ö - void (*sayHello)(Animal* t); // к - void (*eat)(Animal* t); // ﶼԣ󷽷ʵ֣ - void (*breathe)(Animal* t); // ﶼ󷽷ʵ֣ - void (*init)(Animal* t, const char* name, int age); // ʼdzƺ + void (*setName)(Animal* t, const char* name); // 设置动物的昵称 + void (*setAge)(Animal* t, int age); // 设置动物的年龄 + void (*sayHello)(Animal* t); // 动物打招呼 + void (*eat)(Animal* t); // 动物都会吃(抽象方法,由子类实现) + void (*breathe)(Animal* t); // 动物都会呼吸(抽象方法,由子类实现) + void (*init)(Animal* t, const char* name, int age); // 初始化昵称和年龄 }; CLASS(Fish) { - EXTENDS(Animal); // ̳Animal - IMPLEMENTS(IMoveable); // ʵIMoveableӿ + EXTENDS(Animal); // 继承Animal抽象类 + IMPLEMENTS(IMoveable); // 实现IMoveable接口 void (*init)(Fish* t, const char* name, int age); }; CLASS(Dog) { - EXTENDS(Animal); // ̳Animal - IMPLEMENTS(IMoveable); // ʵIMoveableӿ + EXTENDS(Animal); // 继承Animal抽象类 + IMPLEMENTS(IMoveable); // 实现IMoveable接口 void(*init)(Dog* t, const char* name, int age); @@ -40,7 +40,7 @@ CLASS(Dog) CLASS(Car) { - IMPLEMENTS(IMoveable); // ʵIMoveableӿڣӲǶMove + IMPLEMENTS(IMoveable); // 实现IMoveable接口(车子不是动物,但可以Move) }; #endif \ No newline at end of file diff --git a/demo/Animal/lw_oopc.c b/demo/Animal/lw_oopc.c deleted file mode 100644 index c3df63d..0000000 --- a/demo/Animal/lw_oopc.c +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. -// Released under the terms of the GNU Library or Lesser General Public License (LGPL). -// Author: Tom Kao(߻)MISOOŶӣYonghua Jin() -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include -#include -#include -#include "lw_oopc.h" - -#ifdef LW_OOPC_PRINT_DEBUG_INFO -#define lw_oopc_dbginfo printf -#else -#define lw_oopc_dbginfo -#endif - -#define LW_OOPC_MAX_PATH (260) -#define LW_OOPC_MEMORY_DETECTOR_RST "memory_detector_result.txt" - -typedef struct LW_OOPC_MemAllocUnit -{ - char file[LW_OOPC_MAX_PATH]; // ļ - int line; // к - void* addr; // ڴַ - size_t size; // ڴС - struct LW_OOPC_MemAllocUnit* next; // һڴ -} LW_OOPC_MemAllocUnit; - -#ifdef LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR - -static LW_OOPC_MemAllocUnit* lw_oopc_memAllocList = 0; - -void* lw_oopc_malloc(size_t size, const char* type, const char* file, int line) { - void* addr = malloc(size); - if (addr != 0) { - LW_OOPC_MemAllocUnit* pMemAllocUnit = malloc(sizeof(LW_OOPC_MemAllocUnit)); - if (!pMemAllocUnit) { - fprintf(stderr, "lw_oopc: error! malloc alloc unit failed.\n"); - exit(1); - } - - if (strlen(file) >= LW_OOPC_MAX_PATH) { - fprintf(stderr, "lw_oopc: error! file name is more than %d character: %s\n", LW_OOPC_MAX_PATH, file); - exit(1); - } - - strcpy(pMemAllocUnit->file, file); - - pMemAllocUnit->line = line; - pMemAllocUnit->addr = addr; - pMemAllocUnit->size = size; - pMemAllocUnit->next = lw_oopc_memAllocList; - lw_oopc_memAllocList = pMemAllocUnit; - - lw_oopc_dbginfo("lw_oopc: alloc memory in %p, size: %lu, object type: %s, file: %s, line: %d\n", addr, size, type, file, line); - } - - return addr; -} - -void lw_oopc_free(void* memblock) { - LW_OOPC_MemAllocUnit* prevUnit = 0; - LW_OOPC_MemAllocUnit* currUnit = lw_oopc_memAllocList; - - while (currUnit != 0) { - if (currUnit->addr == memblock) { - lw_oopc_dbginfo("lw_oopc: free memory in %p, size: %lu\n", currUnit->addr, currUnit->size); - if (prevUnit == 0) { - lw_oopc_memAllocList = currUnit->next; - free(currUnit->addr); - return; - } - - prevUnit->next = currUnit->next; - return; - } else { - prevUnit = currUnit; - currUnit = currUnit->next; - } - } - - if (currUnit == 0) { - fprintf(stderr, "lw_oopc: error! you attemp to free invalid memory.\n"); - exit(1); - } -} - -void lw_oopc_report() { - LW_OOPC_MemAllocUnit* currUnit = lw_oopc_memAllocList; - FILE* fp = fopen(LW_OOPC_MEMORY_DETECTOR_RST, "w+"); - - if (!fp) { - fprintf(stderr, "lw_oopc: error occured, open file: %s failed.\n", LW_OOPC_MEMORY_DETECTOR_RST); - } - - if (currUnit != 0) { - fprintf(stderr, "lw_oopc: memory leak:\n"); - if (fp) { - fprintf(fp, "lw_oopc: memory leak:\n"); - } - - while (currUnit != 0) { - fprintf(stderr, "memory leak in: %p, size: %lu, file: %s, line: %d\n", currUnit->addr, currUnit->size, currUnit->file, currUnit->line); - if (fp) { - fprintf(fp, "memory leak in: %p, size: %lu, file: %s, line: %d\n", currUnit->addr, currUnit->size, currUnit->file, currUnit->line); - } - currUnit = currUnit->next; - } - } else { - printf("lw_oopc: no memory leak.\n"); - if (fp) { - fprintf(fp, "lw_oopc: no memory leak.\n"); - } - } - - if (fp) { - fclose(fp); - } -} -#else - -void lw_oopc_report() { -} - -#endif diff --git a/demo/Animal/lw_oopc.h b/demo/Animal/lw_oopc.h index 9205943..2b6e00f 100755 --- a/demo/Animal/lw_oopc.h +++ b/demo/Animal/lw_oopc.h @@ -1,6 +1,6 @@ -// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. +// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. // Released under the terms of the GNU Library or Lesser General Public License (LGPL). -// Author: Tom Kao(߻)MISOOŶӣYonghua Jin() +// Author: Tom Kao(中文名:高焕堂),MISOO团队,Yonghua Jin(中文名:金永华) // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -29,17 +29,15 @@ #include -// ú(ѡһ): -// LW_OOPC_USE_STDDEF_OFFSETOF ʾʹC׼offsetof -// LW_OOPC_USE_USER_DEFINED_OFFSETOF ʾʹûԶlw_oopc_offsetof -#define LW_OOPC_USE_STDDEF_OFFSETOF -//#define LW_OOPC_USE_USER_DEFINED_OFFSETOF +// 配置宏(两种配置选其一): +#define LW_OOPC_USE_STDDEF_OFFSETOF // 表示使用C标准定义的offsetof +// #define LW_OOPC_USE_USER_DEFINED_OFFSETOF // 表示使用用户自定义的lw_oopc_offsetof宏 -// Ƿ֧ڴй¶⣬ȱʡ֧ -//#define LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR +// 是否支持内存泄露检测,缺省不支持 +// #define LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR -// Ƿֵ֧Ϣӡ(ڴͷŵϸϢȱʡرմӡ -//#define LW_OOPC_PRINT_DEBUG_INFO +// 是否支持调试信息打印(内存分配和释放的详细信息),缺省关闭打印 +// #define LW_OOPC_PRINT_DEBUG_INFO #ifdef LW_OOPC_USE_STDDEF_OFFSETOF #include @@ -47,7 +45,7 @@ #endif #ifdef LW_OOPC_USE_USER_DEFINED_OFFSETOF -// Щ֧֣ܲμٳ +// 有些环境可能不支持,不过,这种情形极少出现 #define LW_OOPC_OFFSETOF(s,m) (size_t)&(((s*)0)->m) #endif diff --git a/demo/Animal/main.c b/demo/Animal/main.c index a1c2c80..49594b4 100755 --- a/demo/Animal/main.c +++ b/demo/Animal/main.c @@ -1,39 +1,39 @@ -#include "animal.h" +#include "animal.h" int main() { - Fish* fish = Fish_new(); // - Dog* dog = Dog_new(); // - Car* car = Car_new(); // Ӷ + Fish* fish = Fish_new(); // 创建鱼对象 + Dog* dog = Dog_new(); // 创建狗对象 + Car* car = Car_new(); // 创建车子对象 - Animal* animals[2] = { 0 }; // ʼAnimalָ) - IMoveable* moveObjs[3] = { 0 }; // ʼƶIMoveableָ) + Animal* animals[2] = { 0 }; // 初始化动物容器(这里是Animal指针数组) + IMoveable* moveObjs[3] = { 0 }; // 初始化可移动物体容器(这里是IMoveable指针数组) - int i = 0; // ijѭ + int i = 0; // i和j是循环变量 int j = 0; - // ʼdzΪС㣬Ϊ1 - fish->init(fish, "С", 1); + // 初始化鱼对象的昵称为:小鲤鱼,年龄为:1岁 + fish->init(fish, "小鲤鱼", 1); - // fishָתΪAnimalָ룬ֵanimalsĵһԱ + // 将fish指针转型为Animal类型指针,并赋值给animals数组的第一个成员 animals[0] = SUPER_PTR(fish, Animal); - // ʼdzΪȮΪ2 - dog->init(dog, "Ȯ", 2); + // 初始化狗对象的昵称为:牧羊犬,年龄为:2岁 + dog->init(dog, "牧羊犬", 2); - // dogָתΪAnimalָ룬ֵanimalsĵڶԱ + // 将dog指针转型为Animal类型指针,并赋值给animals数组的第二个成员 animals[1] = SUPER_PTR(dog, Animal); - // fishָתΪIMoveableӿָ룬ֵmoveObjsĵһԱ + // 将fish指针转型为IMoveable接口类型指针,并赋值给moveObjs数组的第一个成员 moveObjs[0] = SUPER_PTR(fish, IMoveable); - // dogָתΪIMoveableӿָ룬ֵmoveObjsĵڶԱ + // 将dog指针转型为IMoveable接口类型指针,并赋值给moveObjs数组的第二个成员 moveObjs[1] = SUPER_PTR(dog, IMoveable); - // carָתΪIMoveableӿָ룬ֵmoveObjsĵԱ + // 将car指针转型为IMoveable接口类型指针,并赋值给moveObjs数组的第三个成员 moveObjs[2] = SUPER_PTR(car, IMoveable); - // ѭӡڵĶϢ + // 循环打印动物容器内的动物信息 for (i = 0; i < 2; ++i) { Animal* animal = animals[i]; @@ -42,7 +42,7 @@ int main() animal->sayHello(animal); } - // ѭӡƶڵĿƶƶʽϢ + // 循环打印可移动物体容器内的可移动物体移动方式的信息 for (j = 0; j < 3; ++j) { IMoveable* moveObj = moveObjs[j]; diff --git a/demo/Expr/expr.c b/demo/Expr/expr.c index 00b366f..b162dfe 100755 --- a/demo/Expr/expr.c +++ b/demo/Expr/expr.c @@ -1,22 +1,22 @@ -#include +#include #include #include "expr.h" ABS_CTOR(Expr_node) -cthis->use = 1; // 캯УüʼΪ1 +cthis->use = 1; // 构造函数中,将引用计数初始化为1 END_ABS_CTOR -// Expr_nodeDTOR/END_DTORʵ壩 +// Expr_node的析构函数(DTOR/END_DTOR用于实现析构函数语义) DTOR(Expr_node) -if (--cthis->use == 0) { // ݼüΪ0ͷԼ - cthis->finalize(cthis); // ͷڴ֮ǰԴ(ҪͷŵĶ +if (--cthis->use == 0) { // 递减引用计数,如果计数为0,释放自己 + cthis->finalize(cthis); // 释放内存之前先清理资源(其他需要释放的对象) return lw_oopc_true; } return lw_oopc_false; END_DTOR -// ʽһֵӱʽnΪֵ +// 构建整数表达式(包含一个整数值,无子表达式),n为整数值 void Expr_initInt(Expr* expr, int n) { Int_node* intNode = Int_node_new(lw_oopc_file_line); intNode->init(intNode, n); @@ -24,15 +24,15 @@ void Expr_initInt(Expr* expr, int n) { expr->p = SUPER_PTR(intNode, Expr_node); } -// һԪʽһһӱʽopΪopndΪӱʽ +// 构建一元表达式(包含一个操作符,一个子表达式),op为操作符,opnd为子表达式 void Expr_initUnary(Expr* expr, const char* op, Expr* opnd) { Unary_node* unaryNode = Unary_node_new(lw_oopc_file_line); unaryNode->init(unaryNode, op, opnd); expr->p = SUPER_PTR(unaryNode, Expr_node); } -// һԪʽʽ(ͨһֵһӱʽΪʽһԪʽ -// opΪaΪӱʽֵ +// 构建一元表达式的重载形式(通过传入一个整型值参数,构造一个子表达式为整数表达式的一元表达式) +// op为操作符,a为子表达式的整型值 void Expr_initUnaryX(Expr* expr, const char* op, int a) { Expr* intExpr = Expr_new(lw_oopc_file_line); Unary_node* unaryNode = Unary_node_new(lw_oopc_file_line); @@ -44,16 +44,16 @@ void Expr_initUnaryX(Expr* expr, const char* op, int a) { Expr_delete(intExpr); } -// Ԫʽһӱʽ -// opΪleftΪӱʽrightΪӱʽ +// 构建二元表达式(包含一个操作符,二个子表达式) +// op为操作符,left为左子表达式,right为右子表达式 void Expr_initBinary(Expr* expr, const char* op, Expr* left, Expr* right) { Binary_node* binaryNode = Binary_node_new(lw_oopc_file_line); binaryNode->init(binaryNode, op, left, right); expr->p = SUPER_PTR(binaryNode, Expr_node); } -// Ԫʽʽ(ֵͨӱʽΪʽĶԪʽ -// opΪaΪӱʽֵbΪӱʽֵ +// 构建二元表达式的重载形式(通过传入两个整型值参数,构造两个子表达式均为整数表达式的二元表达式) +// op为操作符,a为左子表达式的整型值,b为右子表达式的整型值 void Expr_initBinaryX(Expr* expr, const char* op, int a, int b) { Expr* left = Expr_new(lw_oopc_file_line); Expr* right = Expr_new(lw_oopc_file_line); @@ -69,7 +69,7 @@ void Expr_initBinaryX(Expr* expr, const char* op, int a, int b) { Expr_delete(right); } -// ӡʽ +// 打印表达式(子树) void Expr_print(Expr* t) { Expr_node* p = t->p; p->print(p); @@ -82,12 +82,12 @@ FUNCTION_SETTING(initUnaryX, Expr_initUnaryX); FUNCTION_SETTING(initBinary, Expr_initBinary); FUNCTION_SETTING(initBinaryX, Expr_initBinaryX); FUNCTION_SETTING(print, Expr_print); -cthis->use = 1; // 캯УüʼΪ1 +cthis->use = 1; // 构造函数中,将引用计数初始化为1 END_CTOR -// ExprDTOR/END_DTORʵ壩 +// Expr的析构函数(DTOR/END_DTOR用于实现析构函数语义) DTOR(Expr) -if (--cthis->use == 0) { // ݼüΪ0ͷԼ +if (--cthis->use == 0) { // 递减引用计数,如果计数为0,释放自己 Expr_node_delete(cthis->p); return lw_oopc_true; } @@ -95,20 +95,20 @@ if (--cthis->use == 0) { // return lw_oopc_false; END_DTOR -// ʽڵijʼ +// 整数表达式节点的初始化 void Int_node_init(Int_node* t, int k) { t->n = k; } -// ʽڵĴӡ +// 整数表达式节点的打印 void Int_node_print(Expr_node* t) { Int_node* cthis = SUB_PTR(t, Expr_node, Int_node); printf("%d", cthis->n); } -// ʽڵԴ +// 整数表达式节点的资源清理 void Int_node_finalize(Expr_node* t) { - // ʲôҪ + // 什么都不需要做 } CTOR(Int_node) @@ -118,20 +118,20 @@ FUNCTION_SETTING(Expr_node.print, Int_node_print); FUNCTION_SETTING(Expr_node.finalize, Int_node_finalize); END_CTOR -// ýڵIJ +// 设置节点的操作符 void setOp(char* opAddr, const char* opValue) { memset(opAddr, 0, 3); strncpy(opAddr, opValue, 2); } -// һԪʽڵijʼ +// 一元表达式节点的初始化 void Unary_node_init(Unary_node* t, const char* opValue, Expr* b) { setOp(t->op, opValue); t->opnd = b; - ++b->use; // ָ븳ֵʱָָü + ++b->use; // 指针赋值时,将指针所指对象的引用计数自增 } -// һԪʽڵĴӡ +// 一元表达式节点的打印 void Unary_node_print(Expr_node* t) { Unary_node* cthis = SUB_PTR(t, Expr_node, Unary_node); Expr* opnd = cthis->opnd; @@ -142,7 +142,7 @@ void Unary_node_print(Expr_node* t) { printf(")"); } -// һԪʽڵԴ +// 一元表达式节点的资源清理 void Unary_node_finalize(Expr_node* t) { Unary_node* cthis = SUB_PTR(t, Expr_node, Unary_node); @@ -156,16 +156,16 @@ FUNCTION_SETTING(Expr_node.print, Unary_node_print); FUNCTION_SETTING(Expr_node.finalize, Unary_node_finalize); END_CTOR -// Ԫʽڵijʼ +// 二元表达式节点的初始化 void Binary_node_init(Binary_node* t, const char* opValue, Expr* left, Expr* right) { setOp(t->op, opValue); t->left = left; t->right = right; - ++left->use; // ָ븳ֵʱָָü - ++right->use; // ָ븳ֵʱָָü + ++left->use; // 指针赋值时,将指针所指对象的引用计数自增 + ++right->use; // 指针赋值时,将指针所指对象的引用计数自增 } -// ԪʽڵĴӡ +// 二元表达式节点的打印 void Binary_node_print(Expr_node* t) { Binary_node* cthis = SUB_PTR(t, Expr_node, Binary_node); @@ -179,7 +179,7 @@ void Binary_node_print(Expr_node* t) { printf(")"); } -// ԪʽڵԴ +// 二元表达式节点的资源清理 void Binary_node_finalize(Expr_node* t) { Binary_node* cthis = SUB_PTR(t, Expr_node, Binary_node); diff --git a/demo/Expr/expr.h b/demo/Expr/expr.h index 8cfd774..2719968 100755 --- a/demo/Expr/expr.h +++ b/demo/Expr/expr.h @@ -1,72 +1,72 @@ -#ifndef EXPR_H_INCLUDED_ +#ifndef EXPR_H_INCLUDED_ #define EXPR_H_INCLUDED_ #include "lw_oopc.h" -// ʽڵ +// 表达式节点 ABS_CLASS(Expr_node) { - int use; // ü + int use; // 引用计数 - void (* print)(Expr_node* t); // ӡʽڵ - void (* finalize)(Expr_node* t); // ͨдfinalizeʵֶԴΪĶ + void (* print)(Expr_node* t); // 打印表达式节点 + void (* finalize)(Expr_node* t); // 子类通过覆写finalize方法,实现对资源清理行为的定制 }; -// ʽĸУinit*ṩ˹ĸ߲APIûʹ +// 表达式(子树的概念),其中,init*方法族提供了构建子树的高层API,方便用户使用 CLASS(Expr) { - int use; // ü - Expr_node* p; // ĸڵ + int use; // 引用计数 + Expr_node* p; // 子树的根节点 - // ʽһֵӱʽ + // 构建整数表达式(包含一个整数值,无子表达式) void (* initInt)(Expr* t, int); - // һԪʽһһӱʽ + // 构建一元表达式(包含一个操作符,一个子表达式) void (* initUnary)(Expr* t, const char*, Expr*); - // һԪʽʽ(ͨһֵһӱʽΪʽһԪʽ + // 构建一元表达式的重载形式(通过传入一个整型值参数,构造一个子表达式为整数表达式的一元表达式) void (* initUnaryX)(Expr* t, const char*, int); - // Ԫʽһӱʽ + // 构建二元表达式(包含一个操作符,二个子表达式) void (* initBinary)(Expr* t, const char*, Expr*, Expr*); - // Ԫʽʽ(ֵͨӱʽΪʽĶԪʽ + // 构建二元表达式的重载形式(通过传入两个整型值参数,构造两个子表达式均为整数表达式的二元表达式) void (* initBinaryX)(Expr* t, const char*, int, int); - // Ԫʽһӱʽ + // 构建三元表达式(包含一个操作符,三个子表达式) void (* initTernary)(Expr* t, const char*, Expr*, Expr*, Expr*); - // Ԫʽʽ(ֵͨӱʽΪʽԪʽ + // 构建三元表达式的重载形式(通过传入三个整型值参数,构造三个子表达式均为整数表达式的三元表达式) void (* initTernaryX)(Expr* t, const char*, int, int, int); - void (* print)(Expr* t); // ӡ + void (* print)(Expr* t); // 打印子树 }; -// ʽڵ +// 整数表达式节点 CLASS(Int_node) { - EXTENDS(Expr_node); // ̳Expr_node + EXTENDS(Expr_node); // 继承Expr_node - int n; // ֵ + int n; // 整数值 - // ʼʽڵ㣨ֵ + // 初始化整数表达式节点(传入整数值) void (* init)(Int_node* t, int k); }; -// һԪʽڵ +// 一元表达式节点 CLASS(Unary_node) { - EXTENDS(Expr_node); // ̳Expr_node + EXTENDS(Expr_node); // 继承Expr_node - char op[3]; // 2ַ - Expr* opnd; // ӱʽ + char op[3]; // 假设操作符最长不超过2个字符 + Expr* opnd; // 子表达式 - // ʼһԪʽڵ㣨1ӱʽ + // 初始化一元表达式节点(传入操作符和1个子表达式) void (* init)(Unary_node* t, const char* a, Expr* b); }; -// Ԫʽڵ +// 二元表达式节点 CLASS(Binary_node) { - EXTENDS(Expr_node); // ̳Expr_node + EXTENDS(Expr_node); // 继承Expr_node - char op[3]; // 2ַ - Expr* left; // ӱʽ - Expr* right; // ӱʽ + char op[3]; // 假设操作符最长不超过2个字符 + Expr* left; // 左子表达式 + Expr* right; // 右子表达式 - // ʼԪʽڵ㣨һӱʽ + // 初始化二元表达式节点(传入一个操作符和两个子表达式) void (* init)(Binary_node* t, const char* a, Expr* b, Expr* c); }; diff --git a/demo/Expr/lw_oopc.c b/demo/Expr/lw_oopc.c index c3df63d..dc3dfac 100755 --- a/demo/Expr/lw_oopc.c +++ b/demo/Expr/lw_oopc.c @@ -1,6 +1,6 @@ -// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. +// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. // Released under the terms of the GNU Library or Lesser General Public License (LGPL). -// Author: Tom Kao(߻)MISOOŶӣYonghua Jin() +// Author: Tom Kao(中文名:高焕堂),MISOO团队,Yonghua Jin(中文名:金永华) // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -40,11 +40,11 @@ typedef struct LW_OOPC_MemAllocUnit { - char file[LW_OOPC_MAX_PATH]; // ļ - int line; // к - void* addr; // ڴַ - size_t size; // ڴС - struct LW_OOPC_MemAllocUnit* next; // һڴ + char file[LW_OOPC_MAX_PATH]; // 文件名 + int line; // 行号 + void* addr; // 内存地址 + size_t size; // 内存块大小 + struct LW_OOPC_MemAllocUnit* next; // 下一个内存块 } LW_OOPC_MemAllocUnit; #ifdef LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR diff --git a/demo/Expr/lw_oopc.h b/demo/Expr/lw_oopc.h index 9205943..2b6e00f 100755 --- a/demo/Expr/lw_oopc.h +++ b/demo/Expr/lw_oopc.h @@ -1,6 +1,6 @@ -// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. +// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. // Released under the terms of the GNU Library or Lesser General Public License (LGPL). -// Author: Tom Kao(߻)MISOOŶӣYonghua Jin() +// Author: Tom Kao(中文名:高焕堂),MISOO团队,Yonghua Jin(中文名:金永华) // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -29,17 +29,15 @@ #include -// ú(ѡһ): -// LW_OOPC_USE_STDDEF_OFFSETOF ʾʹC׼offsetof -// LW_OOPC_USE_USER_DEFINED_OFFSETOF ʾʹûԶlw_oopc_offsetof -#define LW_OOPC_USE_STDDEF_OFFSETOF -//#define LW_OOPC_USE_USER_DEFINED_OFFSETOF +// 配置宏(两种配置选其一): +#define LW_OOPC_USE_STDDEF_OFFSETOF // 表示使用C标准定义的offsetof +// #define LW_OOPC_USE_USER_DEFINED_OFFSETOF // 表示使用用户自定义的lw_oopc_offsetof宏 -// Ƿ֧ڴй¶⣬ȱʡ֧ -//#define LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR +// 是否支持内存泄露检测,缺省不支持 +// #define LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR -// Ƿֵ֧Ϣӡ(ڴͷŵϸϢȱʡرմӡ -//#define LW_OOPC_PRINT_DEBUG_INFO +// 是否支持调试信息打印(内存分配和释放的详细信息),缺省关闭打印 +// #define LW_OOPC_PRINT_DEBUG_INFO #ifdef LW_OOPC_USE_STDDEF_OFFSETOF #include @@ -47,7 +45,7 @@ #endif #ifdef LW_OOPC_USE_USER_DEFINED_OFFSETOF -// Щ֧֣ܲμٳ +// 有些环境可能不支持,不过,这种情形极少出现 #define LW_OOPC_OFFSETOF(s,m) (size_t)&(((s*)0)->m) #endif diff --git a/demo/Expr/main.c b/demo/Expr/main.c index ccba5b6..75de421 100755 --- a/demo/Expr/main.c +++ b/demo/Expr/main.c @@ -1,4 +1,4 @@ -#include +#include #include "expr.h" int main() { diff --git a/demo/expr-advance/expr.c b/demo/expr-advance/expr.c index 2aedff6..d82d8fc 100644 --- a/demo/expr-advance/expr.c +++ b/demo/expr-advance/expr.c @@ -1,21 +1,21 @@ -#include +#include #include #include "expr.h" ABS_CTOR(Expr_node) -cthis->use = 1; // 캯УüʼΪ1 +cthis->use = 1; // 构造函数中,将引用计数初始化为1 END_ABS_CTOR -// Expr_nodeDTOR/END_DTORʵ壩 +// Expr_node的析构函数(DTOR/END_DTOR用于实现析构函数语义) DTOR(Expr_node) -if (--cthis->use == 0) { // ݼüΪ0ͷԼ - cthis->finalize(cthis); // ͷڴ֮ǰԴ(ҪͷŵĶ +if (--cthis->use == 0) { // 递减引用计数,如果计数为0,释放自己 + cthis->finalize(cthis); // 释放内存之前先清理资源(其他需要释放的对象) return lw_oopc_true; } return lw_oopc_false; END_DTOR -// ʽһֵӱʽnΪֵ +// 构建整数表达式(包含一个整数值,无子表达式),n为整数值 void Expr_initInt(Expr* expr, int n) { Int_node* intNode = Int_node_new(lw_oopc_file_line); intNode->init(intNode, n); @@ -23,15 +23,15 @@ void Expr_initInt(Expr* expr, int n) { expr->p = SUPER_PTR(intNode, Expr_node); } -// һԪʽһһӱʽopΪopndΪӱʽ +// 构建一元表达式(包含一个操作符,一个子表达式),op为操作符,opnd为子表达式 void Expr_initUnary(Expr* expr, const char* op, Expr* opnd) { Unary_node* unaryNode = Unary_node_new(lw_oopc_file_line); unaryNode->init(unaryNode, op, opnd); expr->p = SUPER_PTR(unaryNode, Expr_node); } -// һԪʽʽ(ͨһֵһӱʽΪʽһԪʽ -// opΪaΪӱʽֵ +// 构建一元表达式的重载形式(通过传入一个整型值参数,构造一个子表达式为整数表达式的一元表达式) +// op为操作符,a为子表达式的整型值 void Expr_initUnaryX(Expr* expr, const char* op, int a) { Expr* intExpr = Expr_new(lw_oopc_file_line); Unary_node* unaryNode = Unary_node_new(lw_oopc_file_line); @@ -43,16 +43,16 @@ void Expr_initUnaryX(Expr* expr, const char* op, int a) { Expr_delete(intExpr); } -// Ԫʽһӱʽ -// opΪleftΪӱʽrightΪӱʽ +// 构建二元表达式(包含一个操作符,二个子表达式) +// op为操作符,left为左子表达式,right为右子表达式 void Expr_initBinary(Expr* expr, const char* op, Expr* left, Expr* right) { Binary_node* binaryNode = Binary_node_new(lw_oopc_file_line); binaryNode->init(binaryNode, op, left, right); expr->p = SUPER_PTR(binaryNode, Expr_node); } -// Ԫʽʽ(ֵͨӱʽΪʽĶԪʽ -// opΪaΪӱʽֵbΪӱʽֵ +// 构建二元表达式的重载形式(通过传入两个整型值参数,构造两个子表达式均为整数表达式的二元表达式) +// op为操作符,a为左子表达式的整型值,b为右子表达式的整型值 void Expr_initBinaryX(Expr* expr, const char* op, int a, int b) { Expr* left = Expr_new(lw_oopc_file_line); Expr* right = Expr_new(lw_oopc_file_line); @@ -68,14 +68,14 @@ void Expr_initBinaryX(Expr* expr, const char* op, int a, int b) { Expr_delete(right); } -// Ԫʽһӱʽ +// 构建三元表达式(包含一个操作符,三个子表达式) void Expr_initTernary(Expr* expr, const char* op, Expr* left, Expr* middle, Expr* right) { Ternary_node* ternaryNode = Ternary_node_new(lw_oopc_file_line); ternaryNode->init(ternaryNode, op, left, middle, right); expr->p = SUPER_PTR(ternaryNode, Expr_node); } -// Ԫʽʽ(ֵͨӱʽΪʽԪʽ +// 构建三元表达式的重载形式(通过传入三个整型值参数,构造三个子表达式均为整数表达式的三元表达式) void Expr_initTernaryX(Expr* expr, const char* op, int a, int b, int c) { Expr* left = Expr_new(lw_oopc_file_line); Expr* middle = Expr_new(lw_oopc_file_line); @@ -94,7 +94,7 @@ void Expr_initTernaryX(Expr* expr, const char* op, int a, int b, int c) { Expr_delete(right); } -// ӡʽ +// 打印表达式(子树) void Expr_print(Expr* t) { Expr_node* p = t->p; p->print(p); @@ -109,32 +109,32 @@ FUNCTION_SETTING(initBinaryX, Expr_initBinaryX); FUNCTION_SETTING(initTernary, Expr_initTernary); FUNCTION_SETTING(initTernaryX, Expr_initTernaryX); FUNCTION_SETTING(print, Expr_print); -cthis->use = 1; // 캯УüʼΪ1 +cthis->use = 1; // 构造函数中,将引用计数初始化为1 END_CTOR -// ExprDTOR/END_DTORʵ壩 +// Expr的析构函数(DTOR/END_DTOR用于实现析构函数语义) DTOR(Expr) -if (--cthis->use == 0) { // ݼüΪ0ͷԼ +if (--cthis->use == 0) { // 递减引用计数,如果计数为0,释放自己 Expr_node_delete(cthis->p); return lw_oopc_true; } return lw_oopc_false; END_DTOR -// ʽڵijʼ +// 整数表达式节点的初始化 void Int_node_init(Int_node* t, int k) { t->n = k; } -// ʽڵĴӡ +// 整数表达式节点的打印 void Int_node_print(Expr_node* t) { Int_node* cthis = SUB_PTR(t, Expr_node, Int_node); printf("%d", cthis->n); } -// ʽڵԴ +// 整数表达式节点的资源清理 void Int_node_finalize(Expr_node* t) { - // ʲôҪ + // 什么都不需要做 } CTOR(Int_node) @@ -144,20 +144,20 @@ FUNCTION_SETTING(Expr_node.print, Int_node_print); FUNCTION_SETTING(Expr_node.finalize, Int_node_finalize); END_CTOR -// ýڵIJ +// 设置节点的操作符 void setOp(char* opAddr, const char* opValue) { memset(opAddr, 0, 3); strncpy(opAddr, opValue, 2); } -// һԪʽڵijʼ +// 一元表达式节点的初始化 void Unary_node_init(Unary_node* t, const char* opValue, Expr* b) { setOp(t->op, opValue); t->opnd = b; - ++b->use; // ָ븳ֵʱָָü + ++b->use; // 指针赋值时,将指针所指对象的引用计数自增 } -// һԪʽڵĴӡ +// 一元表达式节点的打印 void Unary_node_print(Expr_node* t) { Unary_node* cthis = SUB_PTR(t, Expr_node, Unary_node); Expr* opnd = cthis->opnd; @@ -168,7 +168,7 @@ void Unary_node_print(Expr_node* t) { printf(")"); } -// һԪʽڵԴ +// 一元表达式节点的资源清理 void Unary_node_finalize(Expr_node* t) { Unary_node* cthis = SUB_PTR(t, Expr_node, Unary_node); @@ -182,16 +182,16 @@ FUNCTION_SETTING(Expr_node.print, Unary_node_print); FUNCTION_SETTING(Expr_node.finalize, Unary_node_finalize); END_CTOR -// Ԫʽڵijʼ +// 二元表达式节点的初始化 void Binary_node_init(Binary_node* t, const char* opValue, Expr* left, Expr* right) { setOp(t->op, opValue); t->left = left; t->right = right; - ++left->use; // ָ븳ֵʱָָü - ++right->use; // ָ븳ֵʱָָü + ++left->use; // 指针赋值时,将指针所指对象的引用计数自增 + ++right->use; // 指针赋值时,将指针所指对象的引用计数自增 } -// ԪʽڵĴӡ +// 二元表达式节点的打印 void Binary_node_print(Expr_node* t) { Binary_node* cthis = SUB_PTR(t, Expr_node, Binary_node); @@ -205,7 +205,7 @@ void Binary_node_print(Expr_node* t) { printf(")"); } -// ԪʽڵԴ +// 二元表达式节点的资源清理 void Binary_node_finalize(Expr_node* t) { Binary_node* cthis = SUB_PTR(t, Expr_node, Binary_node); @@ -220,7 +220,7 @@ FUNCTION_SETTING(Expr_node.print, Binary_node_print); FUNCTION_SETTING(Expr_node.finalize, Binary_node_finalize); END_CTOR -// Ԫʽڵijʼ +// 三元表达式节点的初始化 void Ternary_node_init(Ternary_node* t, const char* opValue, Expr* left, Expr* middle, Expr* right) { setOp(t->op, opValue); //(a); @@ -233,7 +233,7 @@ void Ternary_node_init(Ternary_node* t, const char* opValue, ++right->use; } -// ԪʽڵĴӡ +// 三元表达式节点的打印 void Ternary_node_print(Expr_node* t) { Ternary_node* cthis = SUB_PTR(t, Expr_node, Ternary_node); Expr* left = cthis->left; @@ -249,7 +249,7 @@ void Ternary_node_print(Expr_node* t) { printf(")"); } -// ԪʽڵԴ +// 三元表达式节点的资源清理 void Ternary_node_finalize(Expr_node* t) { Ternary_node* cthis = SUB_PTR(t, Expr_node, Ternary_node); diff --git a/demo/expr-advance/expr.h b/demo/expr-advance/expr.h index 8a0658d..6401201 100644 --- a/demo/expr-advance/expr.h +++ b/demo/expr-advance/expr.h @@ -1,86 +1,86 @@ -#ifndef EXPR_H_INCLUDED_ +#ifndef EXPR_H_INCLUDED_ #define EXPR_H_INCLUDED_ #include "lw_oopc.h" -// ʽڵ +// 表达式节点 ABS_CLASS(Expr_node) { - int use; // ü + int use; // 引用计数 - void (* print)(Expr_node* t); // ӡʽڵ + void (* print)(Expr_node* t); // 打印表达式节点 //int (*eval)(Expr_node* t, int* value); - void (* finalize)(Expr_node* t); // ͨдfinalizeʵֶԴΪĶ + void (* finalize)(Expr_node* t); // 子类通过覆写finalize方法,实现对资源清理行为的定制 }; -// ʽĸУinit*ṩ˹ĸ߲APIûʹ +// 表达式(子树的概念),其中,init*方法族提供了构建子树的高层API,方便用户使用 CLASS(Expr) { - int use; // ü - Expr_node* p; // ĸڵ + int use; // 引用计数 + Expr_node* p; // 子树的根节点 - // ʽһֵӱʽ + // 构建整数表达式(包含一个整数值,无子表达式) void (* initInt)(Expr* t, int); - // һԪʽһһӱʽ + // 构建一元表达式(包含一个操作符,一个子表达式) void (* initUnary)(Expr* t, const char*, Expr*); - // һԪʽʽ(ͨһֵһӱʽΪʽһԪʽ + // 构建一元表达式的重载形式(通过传入一个整型值参数,构造一个子表达式为整数表达式的一元表达式) void (* initUnaryX)(Expr* t, const char*, int); - // Ԫʽһӱʽ + // 构建二元表达式(包含一个操作符,二个子表达式) void (* initBinary)(Expr* t, const char*, Expr*, Expr*); - // Ԫʽʽ(ֵͨӱʽΪʽĶԪʽ + // 构建二元表达式的重载形式(通过传入两个整型值参数,构造两个子表达式均为整数表达式的二元表达式) void (* initBinaryX)(Expr* t, const char*, int, int); - // Ԫʽһӱʽ + // 构建三元表达式(包含一个操作符,三个子表达式) void (* initTernary)(Expr* t, const char*, Expr*, Expr*, Expr*); - // Ԫʽʽ(ֵͨӱʽΪʽԪʽ + // 构建三元表达式的重载形式(通过传入三个整型值参数,构造三个子表达式均为整数表达式的三元表达式) void (* initTernaryX)(Expr* t, const char*, int, int, int); - void (* print)(Expr* t); // ӡ + void (* print)(Expr* t); // 打印子树 }; -// ʽڵ +// 整数表达式节点 CLASS(Int_node) { - EXTENDS(Expr_node); // ̳Expr_node + EXTENDS(Expr_node); // 继承Expr_node - int n; // ֵ + int n; // 整数值 - // ʼʽڵ㣨ֵ + // 初始化整数表达式节点(传入整数值) void (* init)(Int_node* t, int k); }; -// һԪʽڵ +// 一元表达式节点 CLASS(Unary_node) { - EXTENDS(Expr_node); // ̳Expr_node + EXTENDS(Expr_node); // 继承Expr_node - char op[3]; // 2ַ - Expr* opnd; // ӱʽ + char op[3]; // 假设操作符最长不超过2个字符 + Expr* opnd; // 子表达式 - // ʼһԪʽڵ㣨1ӱʽ + // 初始化一元表达式节点(传入操作符和1个子表达式) void (* init)(Unary_node* t, const char* a, Expr* b); }; -// Ԫʽڵ +// 二元表达式节点 CLASS(Binary_node) { - EXTENDS(Expr_node); // ̳Expr_node + EXTENDS(Expr_node); // 继承Expr_node - char op[3]; // 2ַ - Expr* left; // ӱʽ - Expr* right; // ӱʽ + char op[3]; // 假设操作符最长不超过2个字符 + Expr* left; // 左子表达式 + Expr* right; // 右子表达式 - // ʼԪʽڵ㣨2ӱʽ + // 初始化二元表达式节点(传入操作符和2个子表达式) void (* init)(Binary_node* t, const char* a, Expr* b, Expr* c); }; -// Ԫʽڵ +// 三元表达式节点 CLASS(Ternary_node) { EXTENDS(Expr_node); - char op[3]; // 2ַ + char op[3]; // 假设操作符最长不超过2个字符 Expr* left; Expr* middle; Expr* right; - // ʼԪʽڵ㣨3ӱʽ + // 初始化三元表达式节点(传入操作符和3个子表达式) void (* init)(Ternary_node* t, const char* op, Expr* left, Expr* middle, Expr* right); }; diff --git a/demo/expr-advance/lw_oopc.c b/demo/expr-advance/lw_oopc.c index c3df63d..dc3dfac 100644 --- a/demo/expr-advance/lw_oopc.c +++ b/demo/expr-advance/lw_oopc.c @@ -1,6 +1,6 @@ -// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. +// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. // Released under the terms of the GNU Library or Lesser General Public License (LGPL). -// Author: Tom Kao(߻)MISOOŶӣYonghua Jin() +// Author: Tom Kao(中文名:高焕堂),MISOO团队,Yonghua Jin(中文名:金永华) // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -40,11 +40,11 @@ typedef struct LW_OOPC_MemAllocUnit { - char file[LW_OOPC_MAX_PATH]; // ļ - int line; // к - void* addr; // ڴַ - size_t size; // ڴС - struct LW_OOPC_MemAllocUnit* next; // һڴ + char file[LW_OOPC_MAX_PATH]; // 文件名 + int line; // 行号 + void* addr; // 内存地址 + size_t size; // 内存块大小 + struct LW_OOPC_MemAllocUnit* next; // 下一个内存块 } LW_OOPC_MemAllocUnit; #ifdef LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR diff --git a/demo/expr-advance/lw_oopc.h b/demo/expr-advance/lw_oopc.h index ad0d5e6..5eded1f 100644 --- a/demo/expr-advance/lw_oopc.h +++ b/demo/expr-advance/lw_oopc.h @@ -1,6 +1,6 @@ -// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. +// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. // Released under the terms of the GNU Library or Lesser General Public License (LGPL). -// Author: Tom Kao(߻)MISOOŶӣYonghua Jin() +// Author: Tom Kao(中文名:高焕堂),MISOO团队,Yonghua Jin(中文名:金永华) // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -29,17 +29,15 @@ #include -// ú(ѡһ): -// LW_OOPC_USE_STDDEF_OFFSETOF ʾʹC׼offsetof -// LW_OOPC_USE_USER_DEFINED_OFFSETOF ʾʹûԶlw_oopc_offsetof -#define LW_OOPC_USE_STDDEF_OFFSETOF -//#define LW_OOPC_USE_USER_DEFINED_OFFSETOF +// 配置宏(两种配置选其一): +#define LW_OOPC_USE_STDDEF_OFFSETOF // 表示使用C标准定义的offsetof +// #define LW_OOPC_USE_USER_DEFINED_OFFSETOF // 表示使用用户自定义的lw_oopc_offsetof宏 -// Ƿ֧ڴй¶⣬ȱʡ֧ +// 是否支持内存泄露检测,缺省不支持 #define LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR -// Ƿֵ֧Ϣӡ(ڴͷŵϸϢȱʡرմӡ -#define LW_OOPC_PRINT_DEBUG_INFO +// 是否支持调试信息打印(内存分配和释放的详细信息),缺省关闭打印 +// #define LW_OOPC_PRINT_DEBUG_INFO #ifdef LW_OOPC_USE_STDDEF_OFFSETOF #include @@ -47,7 +45,7 @@ #endif #ifdef LW_OOPC_USE_USER_DEFINED_OFFSETOF -// Щ֧֣ܲμٳ +// 有些环境可能不支持,不过,这种情形极少出现 #define LW_OOPC_OFFSETOF(s,m) (size_t)&(((s*)0)->m) #endif diff --git a/demo/expr-advance/main.c b/demo/expr-advance/main.c index f91bf01..2aecd33 100644 --- a/demo/expr-advance/main.c +++ b/demo/expr-advance/main.c @@ -1,4 +1,4 @@ -#include +#include #include "expr.h" int main() { diff --git a/demo/expr-advance/memory_detector_result.txt b/demo/expr-advance/memory_detector_result.txt deleted file mode 100644 index c964582..0000000 --- a/demo/expr-advance/memory_detector_result.txt +++ /dev/null @@ -1,5 +0,0 @@ -lw_oopc: memory leak: -memory leak in: 0x1ab6950, size: 40, file: expr.c, line: 20 -memory leak in: 0x1ab67e0, size: 48, file: expr.c, line: 37 -memory leak in: 0x1ab6650, size: 80, file: expr.c, line: 36 -memory leak in: 0x1ab6010, size: 80, file: main.c, line: 5 diff --git a/doc/轻量级的面向对象C语言编程框架介绍.doc b/doc/轻量级的面向对象C语言编程框架介绍.doc index d043cb2bd0ed0f8d0c72e90014217e665f431ca7..7f5c511fa0b0522e76b46787352af673eef8354a 100755 GIT binary patch delta 12326 zcmb{22|QQX|3C11uBA_sB#BZXNhM1P2_Z@pk|eE)EZIVm=z~-;C8cq-j3go<**+?5 zC@rGJh*lYu8kN!BD8JXiXQt^p{lEYJ|M9!^{G4;QbKd8id++DE_Y;}kFS44Kpsjw8 z>7Aq*rT|$2U%R@x=+a*x1v=n_>p`+Bpzm&0)Ox`AzM>5C(cv5xW5SM@cno7v%`j5T z3hx!(cKz)7buazLhbT{unW#>f39dc7%oB;&h(sS&gD>db@TpkO_B6E{)RX@|rLx}? zkC3}#UfH|fzoj{7+xUXJj3S?9nA=zpjTQ6ddP@CKsy&2ZYOu*yq!vic zju%0rqS)VwgBA7^2TGXA}!X%~Du z=__M^^(F}8`_I*X*B6JOd8dh?;B+*I4gZOD&njU}!qH_UBLaOTYw1DSJqefZRb-fE zEE$OXRC?FZDQvCm`3sW&e>n%b$oHl8c3f+`W->1S+8={ZSQWN{4#4v`) zjpBd5p>ST<24T1UDDAEdAHqKRKK(E2`9Iw8`-1*o=Y^drY|y`_lHYa}2E%0Hzi-Dd z^m3tv%?Hb%>u_j@F*5k-(&Nr42hAiP4>wu{ij{wpbPv@}rPj>7>I!5n5l z02IMPkl4X6lJGh4P_#ngtLR0ExzYU#Uu|DNEU`8eB4IaVLk`eArLcz_Sb+mL!eYpR zZ0LY-@eHF8Ul6(l)?0Vd!E!4LwE?$q9?y;^&x{7iXq zd2wxV{;}=8^YE`QvObFNQ6Mc$SO_g(1<(TGApz2$8g2la%rK(h4ey~7zJkkMoZb)u z+0X>dFk&CWEQRHe0-uHF1x+zi7};%!rIQ%+}T9EFj05d=2c2Q>O>pwYho+5#m|2M2Hl zPoS+yg)FFtCTNBiz}t^t!3TmN9r7R_O5rS2LLEpPK;W=c79SR13-;g)G0+MxpaWEK z)1V33U;rjy0ajoOj^G5&upAN~6|#OQe0YBp;UhK%b<)_bLUnKb;l0%ecc;4?>D~>o zB7F$WV1WA-Lx_eLC;=AtI6RO5C9nW1NP$#%LwmS)Dm>^ZMiNs!7bP}5Qs$#TTKG^D zLJKtlbMS!xpcQNfT1hFKhc@T{VP%oMm82ofhD%TlPoWjs;Uhe*%BtE{6_C}PY^&;? zEsSi6BJRB#8Kp9eDa1fKyoZkhV3El%;SdRR&;WN~BF^$jV4Ib=%X1y~fF)xR zb3IEEn>L6iE@veY6V}NlHoqKcj1XFS!w`m$iV)JFp*Iwx-cW*(M#2F|fs%|ulUEhQ z7}@hs374T7XwmT4=%HnXLo529ht{7XN24lX)hWn3qxj|UZME%r zg=(Gmh&C2?^wutc+Jq5EqLy!KesnHlo0pwlh8^zSrWX2q{h1i|#*>V6AEZD&6hIMN zhO1BmH=qGJpeO!f6H-AuG0QuF?-+0ZNALzeNQ3+E5L65Bbq_V5R)`A=I6*KRfKyNg zEud6{yLd1FBXEE>+)b9a2r5`&LZ}C`zix zT;%hh08T*}+=4o|3&NOX5UV`6z;ZYOIq(%k5vMB9wx|~h9K^|SG7Wj!u2tX%IZy=6 zK-={cUO*d+K$~bgpVpkfzkQqhHrYEo6s(~=pbFYx2*RFlMBWLUAr5v! zIvjzlB7va2WdJ{}Ta59EPxz&<0-V!-I2-33VuoD|4|DyV}6^b9EOtB?Yt_Jajj!)$1| zTAWh6wfJgrbVMlrMF*{RTP%niL88c9?6DlW_c)IWD6~T01>C8@5y*zS&;gxbU5>*L z>Y)MJLAC->R^qU)O!R9|6!W(GDMx}bMYh$ z6bH$$7xuw^H~=;91=~=m$m7e1Ndw%mGwF~4M<5fjfR=~5Q-;ejC5i*-9Mz5`uc3td z)s&3n(M33<8Lrcm$al}7TNqB!taq-K&Ka4JaCuon(>W0?qLECXBiu-?@WkI>QHe1Z z)=V~%8{DU6(xvN%MRXbg@-W@j_`H*#3#qVq-beXGC$RBFdTLwKC8@$bVI^(gOcLH>D~16DDeF>vC(Kk+`H*Jmvh_ z^O{D{c!j78x}7ln$N;7fb`%HnKzGY&>uHz&5boDk5*|MN@kzwAx<7Tr=ziUgR0k0L zL=;GS<2)k20Zq^jsDhCOCC~;_u!rRk0FjUYKiZF$tIp#3fl+D&C2adI ze`!Dd|6Ys#zXIi>TmIXQ2IxL#_y|07sXRErMw-V+*;|V<%dCi~uT@`BKPypQ5Yk|z zSjAXl#Qx}FkxI&9c6ls5SZ3wwt?mrd4|y)DjhK<;+$(1?8b_=2OER4(an1{gq69tD za396Y#>L_#(PTTixa^lihsbjGG0V5N5fPQe;Yh1dW}ZJBaIOnEMZ`qU_C?eE{es>7 zf|oh24{#4!q8aMzle6oZZH2b9MW?3e+2&YJ=WQxHzq_t2>(h)Ya^{*>PmXz~nLd8o zq3a9F9X~1Lw=Q*`d~+hzC_`I6g~)p{r?On7>3YRa~@d-V%_${xfQ#E0uG zt+u_;CA<9HwAMkltNDxQOUbS-5$2ygmQkPi>^yo(52H#)Vp*WOPmq=-{fyaJ>s_HO zx%KttGn;Nk%)M11KRQG!BVoGM;RxojI^R=e*u7!=-|yK~iA$X3#iYOfaMbu~-cO$% z?|G&qw=Y|~qIvqXYo3oojL-3-uWU}w9L-x48nET?hI_@!%It3*HoC4eEW@fq`)8Q} zv5j_R4teHoH?K(FvbMZ8X@x33bJv<>cSa_sC^YHKzWq+l;g0_Dyq#HBx(X|_t5fVQ z@Q-Ueu@v>w-@~8n)w1GHmez0c&Lm{HXV;CmQC#||{tFuOpG{r8K1ps9nivQ4;uq}c z?(44g&F36fKUWX;Kzfu&R?m^BP?9!%9C2t}LZkl5)9RKh3a;gye$PxlFx0Fn_13|A zcb@#VNuOWyNcPwLHvJcB9O%^3Bak&PvM_*)Y&7L4*mFxJ~eWvA6%7d9&&4KS+QUX}iQPV8IF zoQRJX)|X|Q%M29#bLGjn{Y$eP3r^)LML1vT(6Fd(?3Dv98n7o8%pCP%(A&0W%a(?}X%gJ~&~#jo^t@HuUUvM^A>nFaE+T96hPDL= zvIhpL+?&l$HLl(_B5PR37n742MwR)F?Wxb_SC8~}ec8z_oujWa*~8y;+35!hz1H21 zc)sQFtF)VAqs{V)?&eOe@onkoA9-});>_D#>#|Q8iJU(>AjM@-+{D!ne)b-pxR7bw zSy*uI=dg^Y&HXyKRX%=2F1cZ&iZ4n`R{HaV-lkw3&SJCm#xkf+`A_A zFj8aVdhtibcbxN1hKfii>{#b1p4c#ejm5r;$hKn_g|G6%CtVFi*an0Nnl`AJ7 zuU83A{7I9Ul;CQ)GF`2&g6qh*lRFMar8KK;3X=$qA+x1!Zdc^%tHzfi?e47o_Uxj^o>A^QH+wnEL^WC*Sm+kq@ zePGw013sjD`MiFL^j#0{nm1Y_zx>g1^G%>_7sm7nEcThQZ*t}1Kd-TG6!>i)u){F{W!bI#LTJipTL-7yh zI!;9vZ!)w4BNrVglpB&Uw={k2;PU$;tISRY>S#8HXg?f(`@y9XiH~Xw$iwQZx7L&m zm#M1u-Li7Ch|HkPZ*|YwSZ!OUufDeVlx4()(IdwOZ%UIplA-+kcGSE%x99Ai6kRs^ zYWSA$sV5pw#k(B%dHor)_ls47#a4~J^r0_5s62Gw&cX3lE#9xGj3ei^&v#zs=C9JJ zk~eCwo1xP7!!-$33rn75GyHzD&c#HXu)clvqS~&XWaC~XT`Ai>MN38hquUv0`!spqp!wpDn*Fx6zE0?)SUcy#TI&PBBd?3!@oY+-G(q}{n}&7Z`dtB; z8#fHnE9Y0*_fI%g@$0}HUE4|(#GaN6wcS}7HSQq)U4G@Obw3x}dHiC zE;;4iV#(*HYiovuD*6xdjBOnC!g$KLF&?j{+10%H{ORr3^;gSHZ-mL6*i@o$`tZql zA7Urg&l@yD(?&Pc#$dyiCC+t!R$okP5#+1J>^zld7PYCLs2+bqLeq;u+2u=P2g%<( zmLex}*)dpYZu#iNa@PZo`s~~P|7cQ2iV2K?)?SEL8b+BfRu2cP(CwOI>us}0h=}2_l5|G@ii6XI+Zs_t6)!J0uLvrTf2n_FM#PC%$|J|j@fZEz_ECOx z!rG(Htg6}2XD#DhuYJ9|N^gnD^;M&Ss(qu!m3_`%b8t<=<0uQO;wX1dn+hXqzD?vs zm&9WJ2`N|O34N>^T0@;Qa!qwQS38+1KB(J$GxlS4a$9*^{4ZbjIgA}SUM1{tz{vg$ z&TY%B&S}nX_plmW_DXwu>bdi$rwsRfb9wZ$qUUk`m6A1iE0bajG8R2ZTR3J>sdD;# z@i)24M|^bhKE38uOI~u)w9yOV+&iZQSsvt%X@BqPm8IKMF>FQDu2*}GRBe`+l5a2L zaBlqa0PXwaSN8R~$2ziu%QE%4`W0k$35-45lS{VPq~AS6WMpeb4VEx3iAtLNZn$#J zzLX_Ssy1SK?WZS^{JBp<_wIKsG+rQW{$6=^;X~nx|8||igO1CO!Huy^= zKJhrte;Fk({?xEaJah2~J&`$bUH2=)jgnKcL(Vm({Bp)}=G#rrljmPM#qJp#A3fvl z`{Q2aeRsNCbJiW9Rj>P-(ocmWDpr_Ck8YRh`<&m@dAQu8a?c49`#;0`ln%bIbBK%l zp8k&S6sCqM%}EGZ!)!`iQgkuhvhl`|!-?@OAoS=rar{iFH5;_>mu2t8I6{gR4;Y9ICYNxX@H-3ntqf1CY^b=WCwNHj@GWe zVSKyKjZUY-ji=u0<4gHJzqb3|OgMYYkL{L`*x-KOYoa-@7~*&ITGdC zvN0c`*YW)QZ=aIhrS>59MsA%*Ov~i{decUwss*JXyGeI^JLZ<6##krv58Q}z z{1lmIaCoOvi^}06W|vRju==nzBK42`B>bZ4nHAC-eq|Jr?DusQelZxj%|mOX+>)aqws%{#!KYO<5)kUXHRX+Nw@r0d#AN&01mKK|RGx7iB4%go1pCx>Mi}&~L z^pELpZuq|6@%tO5zjsu?y<~T%^M7#v^nFp^-@W`@RK2jMZ%gXFmHEDm?+*l82L5oO z(*-;l_~uSXtEW-_dRW-oh;{$*D#nO0OVIu@`V@gNnudEPr4aYPATNJEV-+1uZ51VV zzm@)OUVa|ND)Sv@OfXPU3JP}hb943a_j5N^S??aCGR>qvU&6@MaHUV+9M=FPl;9U+ z=xVIu85|s7sHGLO5;vHxL7M&n?tWOe%0JN8H5jvj9$IdJuIo^;ua6e~-qzFdb@lR7 zQCi`lW31v6tfQh79EzOVYUEaUOr*;u(q+iGtwzpuL{GRxPesYo$IEXunnV*7rB(huRy_-Pb3<3FXqnIs^fJe< zXxaf~kvVQ6LdBVq3JOoX{Gvvc~?gk}zmPKD~ zx8PY;!!bPc$16knMv}g9d=FW8t)-6FPV|*i7O3NjKwsz-mEr*>p1-T%xp+Io;Tbl4 z_MCr#KBL6(VP4(yOim4Psl!+p2O2N|v_KnlKo=$hy$%_GAs7K|pedNabg%?Z@PgIg z1AY(yYakGUU@iWvVnUEv2cZxK;Sd2EArhh>8t7jpn_&xV<%XM*Au>CWO#t*ClL!ot zGs$AL_&dyV;!bF$^dN2j1 zf-y`3jAHk%P(6@(gD?0)Fsz3SFp!>fF%SzFUuGBA_b8i0Lho!kFZK()jb9 zPU4IU=6F4G-1%dy4l&_6jiSVt`uXKT*`Kze}n0b0HY(21_Y6AaYWlM=y~9CiwkszuXOF@mGP(};pYwU`J>65(8rvy=bM4&m~Svy;TLl^G^inQJ=ET5}WgSvgBxZ2KcY zSV#Ta`hP4J?8s+FvUt9Ev49;zRtr8Au*!rBIL^v&N`oh%M2fpu%}zx^uCub7oI6odo=Ue9q1%ZQI-O&g$j{-m2HpLD$OyOi zIy+3-OeTR4h7}b6#c8wxR|PNRl$bgA4DP;uC}G5Oc-!UiG@oRN z&?ne9*Pk?tkFZpx=N~Q`a)jG|oz-Lyi3t+ii4hsX>ys*0gqH)+krU}?3ny+wExU;A z{6c>ktk9ol<4jldZSNXDc-)~{b}SL)5oIr<5pzfge=%y@sBx`RTBq2j{_Mlz(@=EnC`D9#)7a?r-JUJdleJEImVH5A zl2wBWUE|Ja*N1^>f@3K56e6pw5NUblgo?uT)GcC%5PMlvh5CKW7dFl%xrZ8bekr3O{ zhiG^BmT!YSj5gF&&T4RmzI)7ZXQ)W?p)*-u3#&)!ekaVuoVf^! z?Z>2&yN5s3V%tGhFb8LgZ+K6L(@YBcSculnnJO%zkq9PG-B3c+@@hzAxg5eFXY8XQ zZJ!WZJl%J(Ak13il}*e&sa80Lt<_8>lbv6JL}-w#5W4f?5^$g&b?oSF%Jk)@H9t7 zY{m0gcYu8Xl}HQrr9de}S1P=L@ghRCdtGZYwbaeVZR?+s@mh|rjFDcs+MqJ2g27j1 zEoT?btpy0G$A^r%Rf^q7F$^l@mB>TfGL?%EFC!nPaR#OE$zby#2WN2( zSK+suVjvQuF%{Er>iFT~hYub;p1(bRbN=STn>W7s;)I9zmuo%xoYYBBCFV>-B`^vq zfrUuJDiq*DXe-!xFbn+nPHd3(#+H2Goz6eGPVzCmL_)c6Ka$kMI zQ>JG=@kn~nr>%4nREakw5tV2JqLGZrNX3g#nQX-_oJT2~nOPl~tRh^8eJH>goJ9$K zz-Rlj_s`!yIolr0-)|qywVr%Vj&Up$u}X+2q@o0u@B{o`=Kw_*=3xPf&@qda#WZX~ z_-fWiGzMcRM#GBPt8*7U;U&|*ncFmd?q`2|fGjVgBguDy$~qQFNXAr5gDT2gEW{2R zz(E{=S-jl1(>D14qpFnS9Hm=KxB_`NhC-+kH>Q-T)T5wEJqs(5iB(val^a)Vlf8(p zhpJQ__Tmx*717`eXGI4QcUE@P>fG=%`{i9sQuR*4I7~$fX2IMRsxj6rn6TitojFa0 z=019MwH(XLb?{xo9*z*q!b)gs*}X6shj0`1oddrl0<*Wp7GQ>?nn^1euf|3x$r7L^w(^ zmC%Zpu@YO>=0=|1BYP9wg}pd{0;obCfhzbhoQ9yV7Ieq8%H&2~*dy;`lB&~U>_Y*L zxzyz(@gfwzk=wE4xa>!?6qle;ML%>xC{(ovVHiHd5%hSAGbSb@4@Xh>R&M{&ccsp3 zD^jr$1#qr*mU#G^LM%Zk2CwJ*gDX(UO@uSaBgA`bV82ER)?htO;5;tC?`?W$+@N!~ z*s3py__3f$XeQ<%3+tc~+kkB-gi6?%XdsCW#L%~Mqc820V~LKyRHR@Amf;f=A$B9l z!;0Bhh4UzZ&pQ+W{^*26WUKKUmd9c&!S}e7!=AN>J*zK!*6g3}SwFUHM^4V1R}vpi z>LcNrYstpk_Lu)ILz!Ia$lRCAoCWYB6W5GS?OZ*7?1Md4KgdCJUvBc1rLwo9I2nX1 zuo4@QgH1SqgE)i_QHWBQ#m|krx<@84>XXYE215~#ahQlz_yi}>b`vLi976lebSoH! zsdyRNkcVOfZ{ZRfVTiy`e7E!?nYek6jFi0`IW{KMrcgOYA_~qDBod#DOsG<qavMp3iLN?omTIAcZ4{=qiComD~ zu?eT4YIO$Za2_qFk*ejHL+|i!#hi(A26d-ZLTpK1a=Glq9993e2t_!Y+aaF#Fbu~6 zEJhaAAbX1~+=m*DA?{qpoX**RY5i@S8IXkne2B}qf`MBpIZ}~{RXBqs|HZC>e6-lc z!G&;4+?HN6Hz+-GVjbI`edQF{oAkFJ4=S%+IDi<^cILZ;_%f`5D#KNHkw?f@Tcn@d zBY#i4GolfLIH+>1!$urL0S@693Q-JI&a)^%TgurPp$J0;%<|ht_{-Pj?-@UUVqAa^ zb@4|KRQ)0ljYly8qmhh>NW)@eAPZ}djrG`oP1|fE>XF9~;%eSrXz#L3QHpVSbV^u= z(Czdhn1#LY*+H9O7xHlqK0DcVyXbLt(Nm1G<<*z{q)wXojXCM80)Yeo3I5XQ04j_R}f0M!V!TO#9=Vvk%$q{M(5dP2TENgFp>mSsboyX6r^A- zR7GEes;s(aUxH=Gzy|C>A}|ZPp<9oE*X$BVk`7pY9W9F=Y=|X;_1GIDt}JLEK(;LmWdPN)Y%SrQFAE zzb}2_u^`*T7BXGx~8U3y_0N*n+Ld!w&31KK3HsQN~S#TW|)d zypt)HD)UsRa?e2LnS9K`%UFp_tU?x4#j>F)w*edX*fs>qhonwC2Or`Hj^Y>!;oJyT zDy%lZQ8+h11REd{P1y*kn2SuDfY{IRgwaUC6wF2{mLUU2aSUBQ;o~HVa2E9ruyqlM zD2%{Jq+kX%9hI8W9Dw%m?f z{_Jyg(mxp7)c8vaS;w}qtsEkC^2$RYig6ZK5ce1MF$_jLhG8PIu^t<+5$A9oB`8G? z$`OtjILkJexGLXlEJFrmQ)OL=_DA?|7J4NG&O~Dh-4xT1g6KoGHSOgi(uazu%KSrp zG4zGBUAR-8(`0Mg$DO3^*G^h!6JH_Ph}tE7L@j+KpJjab5Y{VEvxV_&FL}4@V0*Kd zTx}V?lqu>fZi6rb%drA4;bpvn!}y71l-G!JZWga23tZQWHCT&mya9W9*^x3RfU6Mu zn40n}@e<>2k+P-gSxTk-3cVU0*q+fn(awzb!RpM9CR)m2oke zG}hUkxnDlm&cjn`#y4YR1LKn<87MQ1Zk%V;! zlL`F^QwZx4S_$hB&Lg~oFwJ;&tbDqzYLh{erc8J&neK&lDH|&<$}Pslag<}H@yvLF z{kDtaWy3MX@Ln>+==PE9NV|>rNM80dYJVg<8L7u*d)1Q1hqt|+UyyV5gCFw$d*{A9PAK+Vh1w^&bO|&1=(2r_xtSANG9CpH z^vO}{)`QX>pSgJ$UoRVzPRk+O+4&f|lB7j?8tkJ28s$!O#9iowyU`iu3K`b6X90p(@ev3hP5Q8y9KFrkyk%ypmo8Ms=9>#DaAQ6w?QT!ew z@E;h7$1nHI#2|Q`^JtLnCn5)%i&y*awb?pu7WebRx(>1?1ivMkyCgOyj#h83v z{?7P%m>eggjL@%TklKYAI*EZ%#;~ttXKj@*=6)@^(7;<6)z!?g(e^)Uv2i^GhhJF$ z(=5UCEp#re+pEriAy|!T<>TgjkMePIzNLKJobOpaZqD~AA2;WF>*W*71$@fK%>`R*rY4y z0bXM>`8T8&Z%Sv{oc*;Gr;B#%mmP)p@4M;gyKqYEF2wwv9J&$g36bWOR)1+xe|>z6 zPfZsZfrnsO+EnuCDHieRW&cB!w|J4bkC?+}EujuxU;8q(1^Lh`seY=Cy*Kg~?TOdr zZ&zk-MBo^j5K=Ps01gwVLvcD%Fh|n^>k2&eIlKRuQoClPJT6G7Srn2DM)w z!BMELpf!8h{pg4O7>v<)0o!l}KAiaiup38k0VVL^P)b@e@2ahAe1@2t*?pFJdv$@fP;s6pC;GCGc)WWsrr{coT*A7#Ew-{vCs8 z2aLzFn1%Ux0c)@upWqVyfu?jdeK83yL3KSj*p0uT7-w)9b-D6ri(UvvKl}!97>=ne zX#dxV45e>*2nlEw%vlPP@DvtfDYoMS9L86;iZZmOcTs)cJJ^Hw@F}h!ur=2J7=n2G z4oMgX9j~d6EhxYTsMUrG1q9*uNX45tf~)A!`-iZZ&=_~)9>n4S%tSuk!#;cuaVNbtg3uFT7=~$>j%C=7E9lhG zJR1xo{1e{AwEQsg1K0R19%^0 z=zI?y3`Su*lJO$mK`y?8XDDf+3%coibjL_MhKYC{^YJR)!rR!0cTtRhE?n?n64Xid zJzT_9l%ZW$&U6@sF_?oDcm$sOuC18Q6w^Fpgh@U>HVW zG-hE1-oOFW>P2&4CSJfooPuXKCm!610hofd$VMLC$2k2yHZi8-Fvdoh7fbIFiryS* zXo?_oM-=)Y8S{~YToZPqM~(=q%1 z+g$mUyXPCH&rNc3sAG-KsWOL2doo#bi}izLn)G-AVuL z`u{36N7b+YZ)LOJ`ZAUD|E@QYu5IahMeDlEt!M1G@A##!|0`>b8oBl)9j;^!tC;t6SH&YoT4^uFEvKw^@Z(P#gJcwBvh)TkHQ_GjQ!EZZzF>8P~Y$ zCA>M^as6M_gj{Rsnt^NF^)Pdt?iydN-@;$MTvu?7yB1o-)zAd3z#qFSc-o0S^=m(W z*h#O^r=5J<9(K}e^l2yehn;Bu8hqNx{b48m{#b)gJGnpXq}S-vPJ#T<8ZHkz={5Sa zll#L?w0{jg?d1Njlg<-OHTSfW`@>Fpv)~$h+KC68u6x)?uhFNS+#hzL{cG@PC-;Y) zbe>|Wxu>1nA9m7f^l2v^Ub^mKC%s0Wc5;8%iT1C-r=8p%cG7vWspg(`a(~!KuhFNS z+#hz*?T?1n)YDGx4?A&1Vm|F;tW1#czkdA7Z-bWnu46}nY-R@CYpTWCNMS5UkV!R_ z->9LNbrr zAT?MWRGh(_=V82%An)bJUb_=y7nQ7+BhD>WhR_^2XgA40&AU+!YMwoZ2Q?2fsa760 zNlMMrRDrtnR#6YLpjHCKF=Ple&ti^Q2^7a*&hu1BJZay1SuDeT3|%{T!Z{6A{ob(} zZyoi@e<|aB?^unuj?}-hU&^@OJ67YZqwdc$#kk2YW!&!_tMS%Rul$!X?)Q$>cu^Mk3^~!%K<9_d0jkk_^<-e41 zzjv(0TSwZzvR}%$-#b?0t)tG5U@G~gO!>Xz^*@ri(GO&*^5Yo2;$O$O-!J|`w~PE4 zh+o6F{W`||e(@K&UF7TXihdoV?ibyE7^AMD!sQC%H7+!zw^1)q1~C?p=p5@|bWD_C z_G>Nm(cGAmARp4KQY~qp7o--reUjIR@9D+}F({kE=gr7`pN?`O+-JJz*# zHja)hGr{bxu61ROZzcY(53g$9=;d9k=3SFrZF#olS>!g(4Y%2++-}C@>($tH`e$== zTmR=Jui(Ue<0I9>>Nw5+JdK)bHhXJ3E+m>s`}Kq)sNphHwA+<$om<+OD_pv~u_{jD zy4efV#nt4Bic;liw|RE6_d_k*ul;Vk3#pQsy_c8O{%xcBwz6R@GtM`b#;F9^$Wz+C z^DB>fsHyjOtA+Sgy82eKfxU+AQ|yVFUr?HfsxKQIiK?h(rmv!AqAH!>n*APPL3yDasp0nrEC@Q7%{pg+c9 z9Fj2slkgO#;Au?7G+s4uytk}#=N}n)7PG(|wRjG*F$bxbi{~-VXcZ|N)n}WDMMwwR zj<+Qk0YAxm^gmO#WxU$tWnORbnz`N73#k*?R%#omcLA$+vBvIFFRnDJ-GQ~$BTx6B z8~CfL;1v#nn@SOZNJQa&^g|NHV;G`I5cC(H+B5sSeKsqC*N3^6|ZNiLH< zwkNMjZ>`Ckz&Ck4l_m;;gIJ=tG{`=d+Nkx?=d~`LYQxHq5T>3v+x25Mbe;+?4 zU0FRz8hxb}&#T)!&9sHu2~}K$9#DffG}MAraob+0^^!&%4{fyZ2M_I_@uj!c!We7O z0;RZK1Wa&2<~7w|1$`qk4lcpoVF-%Z;_Q9=6p%T7;&ncYA%_oY%PEN2qrI z-OWC+ysP;J4E6Slr=rYzde;|SsFYaMuI@-ns55?}P%W>9vM6blVp0?pLs7u~C>h3K zrAE{+Dar_FsSVIanq?M*foeKoLq{0o2&2^Q$@JEa@eoI-j$<`l?c6F1b%a#NKCX^o zH9gg_evD&$p$gUe>r}t>_m*0p=4z|`rePXWG|kJy)8eUlSe~CDf|+dfF`gVHpXpsb z$}~0DS10Vt;Xao4wW&^^&%O2}ygh1Znx|%QN#e_3Eu;%`=L$`F)$-uKbdl0SB_sTO z>e)lJfmH+2XN`H`k%u0n>+v$8TWR+h@^RU~gT;&{kIOc#?(-rQ4^k0kDykN)sR-la zR$8;R!6f#S&%DOGzDH(zB-xi*{KaXnGYvjhT^Ie*XTnHqt#!67e4Mw2H}dh$^xVYT z17}+!DMbL!N{(i!CdQ|2v`5nSdj=VaV`Qku;~fSY|2amsGD_QO(e-_V@1W@u%4YSL dGerMn)<=J^j^cl43N)s)(-ztWca*K<{{nxSPOSg{ diff --git a/doc/轻量级的面向对象C语言编程框架介绍.md b/doc/轻量级的面向对象C语言编程框架介绍.md new file mode 100644 index 0000000..7297483 --- /dev/null +++ b/doc/轻量级的面向对象C语言编程框架介绍.md @@ -0,0 +1,679 @@ + +轻量级的面向对象C语言编程框架LW_OOPC介绍 +======================================== + +### 摘要 + +本文介绍一种轻量级的面向对象的C语言编程框架: LW_OOPC. LW_OOPC是Light-Weight Object-Oriented Programming in(with) C的缩写, 总共一个.h文件, 20个宏, 约130行代码, 非常的轻量级, 但却很好的支持了很多面向对象的特性, 比如继承, 多态. 可以优美的实现面向接口编程. 这个框架是由台湾的高焕堂先生以及他的MISOO团队首创, 之后由我继续改进优化, 最后, 经高焕堂同意以LGPL协议开源(开源网址参见后文). + +用C语言实现OO? 我没听错吗? 这听起来真是太疯狂了!... 大家都知道, C++支持了面向对象和面向泛型编程, 比C要更强大些. 那么, 为什么要在C语言中实践面向对象呢? 为什么不直接使用C++呢? + +### 为什么要用面向对象? + +面向过程方式开发的系统, 代码复杂, 耦合性强, 难以维护. 随着我们所要解决的问题越来越复杂, 代码也变得越来越复杂, 越来越难以掌控. 而面向对象改变了程序员的思维方式, 以更加符合客观世界的方式来认识世界, 通过合理的运用抽象, 封装, 继承和多态, 更好的组织程序, 从而很好地应对这种复杂性. + +### 为什么不直接使用C++? + +C和C++之争由来已久, 可能要持续到它们中的一种去世^_^. C语言以其简洁明快, 功能强大的特点, 深得开发人员的喜爱, 尤其是在嵌入式开发领域, C语言更是占据了绝对老大的地位. 在我看来, 语言只是工具, 作为程序员, 我们要做的是: 选择合适的语言, 解决恰当的问题. 我们要尊重事实, 考虑开发环境(软硬件环境), 考虑团队成员的水平, 从商用工程的角度讲, 选择团队成员擅长的语言进行开发, 风险要小很多. + +一些从Java/C#转到C的程序员们, 无法从面向对象切换到面向过程, 但又必须与C语言同事们在遗留的C系统上开发软件, 他们有时会非常困惑: C语言是面向过程的编程语言, 如何实践面向对象, 甚至面向接口编程呢? 此时, 就非常需要在C语言中实现面向对象的手段, 而LW_OOPC正是应对这一难题的解决之道. + +### LW_OOPC是什么? + +简而言之: LW_OOPC是一套C语言的宏, 总共1个.h文件(如果需要内存泄漏检测支持以及调试打印支持,那么还需要1个.c文件(w_oopc.c,约145行)), 20个宏, 约130行代码. LW_OOPC是一种C语言编程框架, 用于支持在C语言中进行面向对象编程. + +### LW_OOPC宏介绍 + +下面, 先通过一个简单的示例来展示LW_OOPC这套宏的使用方法. 我们要创建这样一些对象: 动物(Animal), 鱼(Fish), 狗(Dog), 车子(Car). 显然, 鱼和狗都属于动物, 都会动. 车子也会动, 但是车子不是动物. 会动是这些对象的共同特征, 但是, 显然它们不属于一个家族. 因此, 我们首先考虑抽象出一个接口(IMoveable), 以描述会动这一行为特征: + +```C +INTERFACE(IMoveable) +{ + void (*move)(IMoveable* t); // Move行为 +}; +``` + +INTERFACE宏用于定义接口, 其成员(方法)均是函数指针类型. +然后, 我们分析Animal, 它应该是抽象类还是接口呢? 动物都会吃, 都需要呼吸, 如果仅仅考虑这两个特征, 显然可以把Animal定为接口. 不过, 这里, 为了展示抽象类在LW_OOPC中如何应用. 我们让Animal拥有昵称和年龄属性, 并且, 让动物和我们打招呼(sayHello方法), 但, 我们不允许用户直接创建Animal对象, 所以, 这里把Animal定为抽象类: + +```C +ABS_CLASS(Animal) +{ + char name[128]; // 动物的昵称(假设小于128个字符) + int age; // 动物的年龄 + + void (*setName)(Animal* t, const char* name); // 设置动物的昵称 + void (*setAge)(Animal* t, int age); // 设置动物的年龄 + void (*sayHello)(Animal* t); // 动物打招呼 + void (*eat)(Animal* t); // 动物都会吃(抽象方法,由子类实现) + void (*breathe)(Animal* t); // 动物都会呼吸(抽象方法,由子类实现) + void (*init)(Animal* t, const char* name, int age); // 初始化昵称和年龄 +}; +``` + +ABS_CLASS宏用于定义抽象类, 允许有成员属性. 代码的含义参见代码注释. 紧接着, 我们来定义Fish和Dog类, 它们都继承动物, 然后还实现了IMoveable接口: + +```C +CLASS(Fish) +{ + EXTENDS(Animal); // 继承Animal抽象类 + IMPLEMENTS(IMoveable); // 实现IMoveable接口 + + void (*init)(Fish* t, const char* name, int age); // 初始化昵称和年龄 +}; + +CLASS(Dog) +{ + EXTENDS(Animal); // 继承Animal抽象类 + IMPLEMENTS(IMoveable); // 实现IMoveable接口 + + void(*init)(Dog* t, const char* name, int age); // 初始化昵称和年龄 +}; +``` + +为了让Fish对象或Dog对象在创建之后, 能够很方便地初始化昵称和年龄, Fish和Dog类均提供了init方法.下面, 我们来定义Car,车子不是动物, 但可以Move, 因此, 让Car实现IMoveable接口即可: + +```C +CLASS(Car) +{ + IMPLEMENTS(IMoveable); // 实现IMoveable接口(车子不是动物,但可以Move) +}; +``` + +接口, 抽象类, 具体类的定义都已经完成了. 下面, 我们开始实现它们. 接口是不需要实现的, 所以IMoveable没有对应的实现代码. Animal是抽象动物接口, 是半成品, 所以需要提供半成品的实现: + +```C +/* 设置动物的昵称*/ +void Animal_setName(Animal* t, const char* name) +{ + // 这里假定name不会超过128个字符, 为简化示例代码, 不做保护(产品代码中不要这样写) + strcpy(t->name, name); +} +/* 设置动物的年龄*/ +void Animal_setAge(Animal* t, int age) +{ + t->age = age; +} +/* 动物和我们打招呼*/ +void Animal_sayHello(Animal* t) +{ + printf("Hello! 我是%s,今年%d岁了!\n", t->name, t->age); +} +/* 初始化动物的昵称和年龄*/ +void Animal_init(Animal* t, const char* name, int age) +{ + t->setName(t, name); + t->setAge(t, age); +} + +ABS_CTOR(Animal) +FUNCTION_SETTING(setName, Animal_setName); +FUNCTION_SETTING(setAge, Animal_setAge); +FUNCTION_SETTING(sayHello, Animal_sayHello); +FUNCTION_SETTING(init, Animal_init); +END_ABS_CTOR +``` + +这里出现了几个新的宏, 我们逐个进行讲解. ABS_CTOR表示抽象类的定义开始, ABS_CTOR(Animal)的含义是Animal抽象类的"构造函数"开始. 在C语言里边其实是没有C++中的构造函数的概念的. LW_OOPC中的CTOR系列宏(CTOR/END_CTOR, ABS_CTOR/END_ABS_CTOR)除了给对象(在C语言中是struct实例)分配内存, 然后, 紧接着要为结构体中的函数指针成员赋值, 这一过程, 也可以称为函数绑定(有点类似C++中的动态联编). 函数绑定的过程由FUNCTION_SETTING宏来完成. +对于Fish和Dog类的实现, 与Animal基本上是类似的, 除了将ABS_CTOR换成了CTOR, 直接参见代码: + +```C +/* 鱼的吃行为 */ +void Fish_eat(Animal* t) +{ + printf("鱼吃水草!\n"); +} +/* 鱼的呼吸行为 */ +void Fish_breathe(Animal* t) +{ + printf("鱼用鳃呼吸!\n"); +} +/* 鱼的移动行为 */ +void Fish_move(IMoveable* t) +{ + printf("鱼在水里游!\n"); +} +/* 初始化鱼的昵称和年龄 */ +void Fish_init(Fish* t, const char* name, int age) +{ + Animal* animal = SUPER_PTR(t, Animal); + animal->setName(animal, name); + animal->setAge(animal, age); +} + +CTOR(Fish) +SUPER_CTOR(Animal); +FUNCTION_SETTING(Animal.eat, Fish_eat); +FUNCTION_SETTING(Animal.breathe, Fish_breathe); +FUNCTION_SETTING(IMoveable.move, Fish_move); +FUNCTION_SETTING(init, Fish_init); +END_CTOR +``` + +上面是Fish的实现, 下面看Dog的实现: + +/* 狗的吃行为 */ +void Dog_eat(Animal* t) +{ + printf("狗吃骨头!\n"); +} +/* 狗的呼吸行为 */ +void Dog_breathe(Animal* t) +{ + printf("狗用肺呼吸!\n"); +} +/* 狗的移动行为 */ +void Dog_move(IMoveable* t) +{ + printf("狗在地上跑!\n"); +} +/* 初始化狗的昵称和年龄 */ +void Dog_init(Dog* t, const char* name, int age) +{ + Animal* animal = SUPER_PTR(t, Animal); + animal->setName(animal, name); + animal->setAge(animal, age); +} + +CTOR(Dog) +SUPER_CTOR(Animal); +FUNCTION_SETTING(Animal.eat, Dog_eat); +FUNCTION_SETTING(Animal.breathe, Dog_breathe); +FUNCTION_SETTING(IMoveable.move, Dog_move); +FUNCTION_SETTING(init, Dog_init); +END_CTOR + +细心的朋友可能已经注意到了, 这里又有一个陌生的宏: SUPER_CTOR未介绍. 这个宏是提供给子类用的, 用于调用其直接父类的构造函数(类似Java语言中的super()调用, 在这里, 其实质是要先调用父类的函数绑定过程, 再调用自身的函数绑定过程), 类似Java那样, SUPER_CTOR如果要出现, 需要是ABS_CTOR或者CTOR下面紧跟的第一条语句. +最后, 我们把Car类也实现了: + +```C +void Car_move(IMoveable* t) +{ + printf("汽车在开动!\n"); +} + +CTOR(Car) +FUNCTION_SETTING(IMoveable.move, Car_move); +END_CTOR +``` + +下面, 我们实现main方法, 以展示LW_OOPC的威力: + +```C +#include "animal.h" + +int main() +{ + Fish* fish = Fish_new(); // 创建鱼对象 + Dog* dog = Dog_new(); // 创建狗对象 + Car* car = Car_new(); // 创建车子对象 + + Animal* animals[2] = { 0 }; // 初始化动物容器(这里是Animal指针数组) + IMoveable* moveObjs[3] = { 0 }; // 初始化可移动物体容器(这里是IMoveable指针数组) + + int i = 0; // i和j是循环变量 + int j = 0; + + // 初始化鱼对象的昵称为:小鲤鱼,年龄为:1岁 + fish->init(fish, "小鲤鱼", 1); + + // 将fish指针转型为Animal类型指针,并赋值给animals数组的第一个成员 + animals[0] = SUPER_PTR(fish, Animal); + + // 初始化狗对象的昵称为:牧羊犬,年龄为:2岁 + dog->init(dog, "牧羊犬", 2); + + // 将dog指针转型为Animal类型指针,并赋值给animals数组的第二个成员 + animals[1] = SUPER_PTR(dog, Animal); + + // 将fish指针转型为IMoveable接口类型指针,并赋值给moveOjbs数组的第一个成员 + moveObjs[0] = SUPER_PTR(fish, IMoveable); + + // 将dog指针转型为IMoveable接口类型指针,并赋值给moveOjbs数组的第二个成员 + moveObjs[1] = SUPER_PTR(dog, IMoveable); + + // 将car指针转型为IMoveable接口类型指针,并赋值给moveOjbs数组的第三个成员 + moveObjs[2] = SUPER_PTR(car, IMoveable); + + // 循环打印动物容器内的动物信息 + for(i=0; i<2; i++) + { + Animal* animal = animals[i]; + animal->eat(animal); + animal->breathe(animal); + animal->sayHello(animal); + } + + // 循环打印可移动物体容器内的可移动物体移动方式的信息 + for(j=0; j<3; j++) + { + IMoveable* moveObj = moveObjs[j]; + moveObj->move(moveObj); + } + + lw_oopc_delete(fish); + lw_oopc_delete(dog); + lw_oopc_delete(car); + + return 0; +} +``` + +从上边的代码中, 我们惊喜地发现, 在C语言中, 借助LW_OOPC, 我们实现了将不同的动物(Fish和Dog对象)装入Animal容器, 然后可以用完全相同的方式调用Animal的方法(比如eat和breathe方法), 而实际调用的是具体的实现类(Fish和Dog)的对应方法. 这正是面向对象中的多态的概念. 同样, 我们可以将Fish对象, Dog对象, 以及Car对象均视为可移动物体, 均装入IMoveable容器, 然后用完全相同的方式调用IMoveable接口的move方法. 看到了吗? 借助LW_OOPC, 在C语言下我们竟然可以轻松地实现面向对象和面向接口编程! + +下面, 再举一个稍微复杂的例子, 它的覆盖面是足够全面的, 足以一瞥面向对象编程的3个要素: 数据抽象, 继承和多态. 通过这个例子, 我们期望展现出LW_OOPC在遭遇问题本身比较复杂的情形下, 是如何从容应对的, 以加深读者对LW_OOPC的认识. (备注: 该问题来自第八章的例子, 有兴趣的读者可以对照参阅). + +### 问题描述 + +此程序涉及的内容是用来表示算术表达式的树. 例如, 表达式(-5) * (3 + 4)对应的树为: + +一个表达式树包括代表常数, 一元运算符和二元运算符的节点. 这样的树结构在编译器和计算器程序中都可能用到. 我们希望能通过调用合适的函数来创建这样的树, 然后打印该树的完整括号化形式. 例如, 我们希望打印 + +``` +((-5)*(3+4)) +(((-5)*(3+4))*((-5)*(3+4))) +``` + +作为输出. 此外, 我们不想为这些表达式的表示形式操心, 更不想关心有关它们内存分配和回收的事宜. +这个程序所做的事情在很多需要处理复杂输入的大型程序中是很典型的, 例如编译器, 编辑器, CAD/CAM系统等. 此类程序中通常要花费很大的精力来处理类似树, 图和类似的数据结构. 这些程序的开发者永远需要面对诸如内存分配, 灵活性和效率之类的问题. 面向对象技术可以把这些问题局部化, 从而确保今后发生的一系列变化不会要求整个程序中的其他各个部分随之做相应调整. + +```C +#include +#include "expr.h" + +int main() +{ + Expr* expr1 = Expr_new(); + Expr* expr2 = Expr_new(); + Expr* expr3 = Expr_new(); + Expr* expr = Expr_new(); + + expr1->initUnaryX(expr1, "-", 5); + expr2->initBinaryX(expr2, "+", 3, 4); + expr3->initBinary(expr3, "*", expr1, expr2); + expr->initBinary(expr, "*", expr3, expr3); + + expr3->print(expr3); + printf("\n"); + expr->print(expr); + printf("\n"); + + Expr_delete(expr); + Expr_delete(expr3); + Expr_delete(expr2); + Expr_delete(expr1); + + return 0; +} +``` + +### 解决方案 + +通过考查这个树结构, 会发现这里有3种节点. 一种表示整数表达式, 包含一个整数值, 无子节点. 另外两个分别表示一元表达式和二元表达式, 包含一个操作符, 分别有一个或两个子节点. 我们希望打印各种节点, 但是具体方式需要视要打印节点的类型而定. 这就是动态绑定的用武之地了: 我们可以定义一个虚函数(print)来指明应当如何打印各种节点. 动态绑定将会负责在运行时基于打印节点的实际类型调用正确的函数. +首先, 我们抽象出"节点"的概念, 抽象类的名字定为Expr_node. 它提供了打印的抽象接口, 所有的实际节点类型均从它派生: + +```C +ABS_CLASS(Expr_node) +{ + void (*print)(Expr_node* t); +}; +``` + +具体类的情形怎样? 这些具体类型中最简单的一类是包含一个整数, 没有子节点的节点: + +```C +CLASS(Int_node) +{ + EXTENDS(Expr_node); + int n; + + void (*init)(Int_node* t, int k); +}; +``` + +其他类型又如何呢? 每个类中都必须存储一个操作符(这倒简单, 本文中假定操作符最长不超过2个字符, 所以, 可以用长度为3的字符数组来保存), 但是如何存储子节点呢? 在运行时之前, 我们并不知道子节点的类型会是什么, 所以我们不能按值存储子节点, 必须存储指针. 这样, 一元和二元节点类如下所示: + +```C +CLASS(Unary_node) +{ + EXTENDS(Expr_node); + char op[3]; // 假设操作符最长不超过2个字符 + Expr_node* opnd; + + void (*init)(Unary_node* t, const char* a, Expr_node* b); +}; + +CLASS(Binary_node) +{ + EXTENDS(Expr_node); + char op[3]; // 假设操作符最长不超过2个字符 + Expr_node* left; + Expr_node* right; + + void (*init)(Binary_node* t, const char* a, Expr_node* b, +Expr_node * c); +}; +``` + +这个设计方案可以用, 不过有一个问题. 用户要处理的不是值, 而是指针, 所以必须记住分配和释放对象. 例如, 我们需要这么创建表达式树: + +```C +Int_node* int_node1 = Int_node_new(); +Int_node* int_node2 = Int_node_new(); +Int_node* int_node3 = Int_node_new(); +Unary_node* unary_node = Unary_node_new(); +Binary_node* binary_node1 = Binary_node_new(); +Binary_node* binary_node = Binary_node_new(); + +int_node1->init(int_node1, 5); +int_node2->init(int_node2, 3); +int_node3->init(int_node3, 4); +unary_node->init(unary_node, "-", int_node1); +binary_node1->init(binary_node1, "+", int_node2, int_node3); +binary_node->init(binary_node, "*", unary_node, binary_node1); + +lw_oopc_delete(int_node1); +…… // 删除创建的其他节点 + +``` + +也就是说, 我们需要去关心每一个节点的创建和释放. 我们不仅把内存管理这类烦心事推给了用户, 而且对用户来说也没有什么方便的办法来处理这些事情. 我们得好好想想办法了. + +这里, 提供一种解决内存管理问题的思路: **引用计数**, 这里是针对指针, 对指针的状况进行计数, 对象创建的时候, 引用计数为1, 凡是指针被赋值了, 该指针所指对象的引用计数就自增一, 每次指针要释放, 都先检查对象的引用计数, 让引用计数自减一, 如果引用计数为0, 则释放该对象. + +另外, 原先的设计不够高层, 用户只能直接针对节点进行操作, 没有提供操作子树的概念(这也是用户代码之所以复杂的原因之一), 我们发现, 通过提供子树的概念, 我们不但能够隐藏Expr_node继承层次, 而且, 对于每一个节点, 我们具备了操纵左子树和右子树的能力(原来只能操作左子节点和右子节点). 而这种功能增强完全是建立在面向对象的机制之上, 我们并没有引入耦合. 在非常自然和轻松的情形下, 我们获得了更好的软件组件之间协作的能力, 这正是面向对象的魅力所在. + +这里, 我们把子树的概念用类Expr来表示, 由于子树此时成了Expr_node具体类的成员, 同样, 左右子树在Expr_node中同样是以指针的方式保存, 所以, 对Expr也需要进行引用计数, 代码直接贴上来, 细节解说参见注释: + +```C +// expr.h +#ifndef EXPR_H_INCLUDED_ +#define EXPR_H_INCLUDED_ + +#include "lw_oopc.h" + +// 表达式节点 +ABS_CLASS(Expr_node) +{ + int use; // 引用计数 + + void (*print)(Expr_node* t); // 打印表达式节点 + void (*finalize)(Expr_node* t); // 子类通过覆写finalize方法,实现对资源清理行为的定制 +}; + +// 表达式(子树的概念), 其中, init*方法族提供了构建子树的高层API. 方便用户使用 +CLASS(Expr) +{ + int use; // 引用计数 + Expr_node* p; // 子树的根节点 + + // 构建整数表达式(包含一个整数值,无子表达式) + void (*initInt)(Expr* t, int); + + // 构建一元表达式(包含一个操作符,一个子表达式) + void (*initUnary)(Expr* t, const char*, Expr*); + // 构建一元表达式的重载形式(通过传入个整型值参数,构造一个子表达式为整数表达式的一元表达式) + void (*initUnaryX)(Expr* t, const char*, int); + + // 构建二元表达式(包含一个操作符,二个子表达式) + void (*initBinary)(Expr* t, const char*, Expr*, Expr*); + // 构建二元表达式的重载形式(通过传入个整型值参数,构造两个子表达式均为整数表达式的二元表达式) + void (*initBinaryX)(Expr* t, const char*, int, int); + + void (*print)(Expr* t); // 打印子树 +}; + +// 整数表达式节点 +CLASS(Int_node) +{ + EXTENDS(Expr_node); // 继承Expr_node + + int n; // 整数值 + + // 初始化整数表达式节点(传入整数值) + void (*init)(Int_node* t, int k); +}; + +// 一元表达式节点 +CLASS(Unary_node) +{ + EXTENDS(Expr_node); // 继承Expr_node + + char op[3]; // 假设操作符最长不超过2个字符 + Expr* opnd; // 子表达式 + + // 初始化一元表达式节点(传入一个操作符和一个子表达式) + void (*init)(Unary_node* t, const char* a, Expr* b); +}; + +// 二元表达式节点 +CLASS(Binary_node) +{ + EXTENDS(Expr_node); // 继承Expr_node + + char op[3]; // 假设操作符最长不超过2个字符 + Expr* left; // 左子表达式 + Expr* right; // 右子表达式 + + // 初始化二元表达式节点(传入一个操作符和两个子表达式) + void (*init)(Binary_node* t, const char* a, Expr* b, Expr* c); +}; + +#endif + +//expr.c +…… // 包含所需头文件 + +ABS_CTOR(Expr_node) + cthis->use = 1; // 构造函数中,将引用计数初始化为 +END_ABS_CTOR + +// Expr_node的析构函数(DTOR/END_DTOR用于实现析构函数语义) +DTOR(Expr_node) + if (--cthis->use == 0) // 递减引用计数,如果计数为,释放自己 + { + cthis->finalize(cthis); // 释放内存之前先清理资源(其他需要释放的对象) + return lw_oopc_true; // 返回true,表示析构成功,可以释放内存 + } + return lw_oopc_false; // 返回false,表示析构失败,不能释放内存 +END_DTOR + +// 构建整数表达式(包含一个整数值,无子表达式),n为整数值 +void Expr_initInt(Expr* expr, int n) +{ + Int_node* intNode = Int_node_new(lw_oopc_file_line); + intNode->init(intNode, n); + + expr->p = SUPER_PTR(intNode, Expr_node); +} + +…… // 因篇幅所限,构建一元表达式、二元表达式以及对应的重载形式的函数实现代码省略 + +// 打印表达式(子树) +void Expr_print(Expr* t) +{ + Expr_node* p = t->p; + p->print(p); +} + +CTOR(Expr) +FUNCTION_SETTING(initInt, Expr_initInt); +FUNCTION_SETTING(initUnary, Expr_initUnary); +FUNCTION_SETTING(initUnaryX, Expr_initUnaryX); +FUNCTION_SETTING(initBinary, Expr_initBinary); +FUNCTION_SETTING(initBinaryX, Expr_initBinaryX); +FUNCTION_SETTING(print, Expr_print); + cthis->use = 1; // 构造函数中,将引用计数初始化为 +END_CTOR + +// Expr的析构函数(DTOR/END_DTOR用于实现析构函数语义) +DTOR(Expr) + if (--cthis->use == 0) // 递减引用计数,如果计数为,释放自己 + { + Expr_node_delete(cthis->p); + return lw_oopc_true; + } + return lw_oopc_false; +END_DTOR + +// 整数表达式节点的初始化 +void Int_node_init(Int_node* t, int k) +{ + t->n = k; +} + +// 整数表达式节点的打印 +void Int_node_print(Expr_node* t) +{ + Int_node* cthis = SUB_PTR(t, Expr_node, Int_node); + printf("%d", cthis->n); +} + +// 整数表达式节点的资源清理 +void Int_node_finalize(Expr_node* t) +{ + // 什么都不需要做 +} + +CTOR(Int_node) +SUPER_CTOR(Expr_node); +FUNCTION_SETTING(init, Int_node_init); +FUNCTION_SETTING(Expr_node.print, Int_node_print); +FUNCTION_SETTING(Expr_node.finalize, Int_node_finalize); +END_CTOR + +…… // 因篇幅所限,一(二)元表达式节点的初始化, 打印, 资源清理, 构造等函数的实现代码省略 + +//main.c +#include "stdio.h" +#include "Expr.h" + +int main() +{ + Expr* expr = Expr_new(); +…… // 创建expr1, expr2, expr3的代码 + + expr1->initUnaryX(expr1, "-", 5); + expr2->initBinaryX(expr2, "+", 3, 4); + expr3->initBinary(expr3, "*", expr1, expr2); + expr->initBinary(expr, "*", expr3, expr3); + + expr3->print(expr3); + printf("\n"); + expr->print(expr); + printf("\n"); + + Expr_delete(expr); + …… // 删除expr3、expr2、expr1的代码 + + return 0; +} +``` + +程序运行效果: + +```bash +liuboyf1@ipc:~/data/custom/aklw_oopc/demo/expr$ ./a.out +((-5)*(3+4)) +(((-5)*(3+4))*((-5)*(3+4))) +``` + +怎么样? 效果还不错吧, 最重要的是, 我们的C语言代码现在已经完全是面向对象的. + +### 方案的可扩展性如何? + +假设我们希望添加一种Ternary_node类型来表示三元操作符, 如?: (也就是if-then-else操作符), 看看, 难度有多大? +事实上, 正是因为前面的设计是面向对象的, 要增加一种节点类型易如反掌: + +```C +// 三元表达式节点 +CLASS(Ternary_node) +{ + EXTENDS(Expr_node); + + char op[3]; // 假设操作符最长不超过2个字符 + Expr* left; + Expr* middle; + Expr* right; + + // 初始化三元表达式节点(传入一个操作符和三个子表达式) + void (*init)(Ternary_node* t, const char* op, Expr* left, Expr* middle, Expr* right); +}; +``` + +在Expr中添加创建三元表达式的方法: + +```C +// 表达式(子树的概念), 其中, init*方法族提供了构建子树的高层API, 方便用户使用 +CLASS(Expr) +{ + int use; // 引用计数 + Expr_node* p; // 子树的根节点 + …… // 既有实现 + // 构建三元表达式(包含一个操作符,三个子表达式) + void (*initTernary)(Expr* t, const char*, Expr*, Expr*, Expr*); + // 构建三元表达式的重载形式(通过传入一个整型值参数,构造三个子表达式均为整数表达式的三元表达式) + void (*initTernaryX)(Expr* t, const char*, int, int, int); + …… // 既有实现 +}; +``` + +请读者参照Binary_node的现有实现, 实现出Ternary_node, 这里不再赘述. 一旦实现出Ternary_node, 我们就可以这样创建表达式树并打印: + +```C +…… // 创建expr1, expr2, expr3, expr对象(指针) + +expr1->initUnaryX(expr1, "-", 0); +expr2->initUnaryX(expr2, "-", 5); +expr3->initBinaryX(expr3, "+", 3, 4); +expr->initTernary(expr, "?:", expr1, expr2, expr3); + +expr->print(expr); +printf("\n"); +``` + +为了支持新的节点类型, 对原有代码的更动很少(仅对Expr类有增加方法), 而且只有新增操作(新增类,新增方法), 但没有修改操作(指修改原有方法), 面向对象的设计赋予了系统极大的弹性, 让程序在应对变化时, 更加从容. 在这个例子中, LW_OOPC帮助我们在C语言的世界里营造出OO的天地, 带领我们再一次领略了面向对象的风采. + +### LW_OOPC最佳实践 + +说得简单一点, 要想使用好LW_OOPC这套宏, 还得首先懂面向对象, 要遵循面向对象设计的那些大原则, 比如开闭原则等. 在C语言中使用面向对象, 根据实际使用的情况, 给出如下建议: + +1. 继承层次不宜过深, 建议最多三层(接口, 抽象类, 具体类, 参见图1和图2) +继承层次过深, 在Java/C#/C++中均不推崇, 在C语言中实践面向对象的时候, 尤其要遵循这一点, 只有这样, 代码才能简单清爽. + +2. 尽量避免多重继承 +尽可能使用单线继承, 但可实现多个接口(与Java中的单根继承类似). + +3. 尽量避免具体类继承具体类 +具体类继承具体类, 不符合抽象的原则, 要尽量避免. + +4. 各继承层次分别维护好自己的数据 +子类尽量不要直接访问祖先类的数据, 如果确实需要访问, 应当通过祖先类提供的函数, 以函数调用的方式间接访问. + +### LW_OOPC的优点 + +1. 轻量级. + +2. 广泛的适应性, 能够适应各种平台, 各种编译器(能支持C的地方, 基本上都能支持). + +3. 帮助懂OO的Java/C++程序员写出面向对象的C程序. + +4. 使用C, 也能引入OO的设计思想和方法, 在团队的C/C++分歧严重时可能非常有用. + +### LW_OOPC的缺点 + +1. 无法支持重载(C语言不支持所致) +2. 不完全的封装(无法区分私有, 保护和公有) +LW_OOPC的INTERFACE/ABS_CLASS/CLASS三个宏展开后都是C语言的struct, 其成员全是公有的, 宏本身并无能力提供良好地封装层次的支持, 所以, 只能从编程规范和编程风格上进行引导. +3. 不支持RTTI +既然不支持RTTI, 那么显然也无法支持安全的向下转型(C++中的dynamic_cast的转型功能) +4. 不支持拷贝构造以及赋值语义 +5. 转换成接口的表述有点麻烦, 表达形式相比C++要啰嗦很多. +6. 有学习成本, 需要用户学习并习惯这套宏. + +前四条缺点, 实质上并非是LW_OOPC的缺点, 而是C相对C++而言的缺点, 在这里, 之所以也一并列上, 是希望用户不要对LW_OOPC抱太高的期望, 毕竟它也只是一套C语言的宏而已, C语言有的缺点, LW_OOPC并不能够解决. + +### 总结 + + + diff --git a/lw_oopc.c b/lw_oopc.c index c3df63d..dc3dfac 100644 --- a/lw_oopc.c +++ b/lw_oopc.c @@ -1,6 +1,6 @@ -// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. +// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. // Released under the terms of the GNU Library or Lesser General Public License (LGPL). -// Author: Tom Kao(߻)MISOOŶӣYonghua Jin() +// Author: Tom Kao(中文名:高焕堂),MISOO团队,Yonghua Jin(中文名:金永华) // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -40,11 +40,11 @@ typedef struct LW_OOPC_MemAllocUnit { - char file[LW_OOPC_MAX_PATH]; // ļ - int line; // к - void* addr; // ڴַ - size_t size; // ڴС - struct LW_OOPC_MemAllocUnit* next; // һڴ + char file[LW_OOPC_MAX_PATH]; // 文件名 + int line; // 行号 + void* addr; // 内存地址 + size_t size; // 内存块大小 + struct LW_OOPC_MemAllocUnit* next; // 下一个内存块 } LW_OOPC_MemAllocUnit; #ifdef LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR diff --git a/lw_oopc.h b/lw_oopc.h index 9205943..2b6e00f 100644 --- a/lw_oopc.h +++ b/lw_oopc.h @@ -1,6 +1,6 @@ -// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. +// Copyright (C) 2008,2009,2010 by Tom Kao & MISOO Team & Yonghua Jin. All rights reserved. // Released under the terms of the GNU Library or Lesser General Public License (LGPL). -// Author: Tom Kao(߻)MISOOŶӣYonghua Jin() +// Author: Tom Kao(中文名:高焕堂),MISOO团队,Yonghua Jin(中文名:金永华) // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -29,17 +29,15 @@ #include -// ú(ѡһ): -// LW_OOPC_USE_STDDEF_OFFSETOF ʾʹC׼offsetof -// LW_OOPC_USE_USER_DEFINED_OFFSETOF ʾʹûԶlw_oopc_offsetof -#define LW_OOPC_USE_STDDEF_OFFSETOF -//#define LW_OOPC_USE_USER_DEFINED_OFFSETOF +// 配置宏(两种配置选其一): +#define LW_OOPC_USE_STDDEF_OFFSETOF // 表示使用C标准定义的offsetof +// #define LW_OOPC_USE_USER_DEFINED_OFFSETOF // 表示使用用户自定义的lw_oopc_offsetof宏 -// Ƿ֧ڴй¶⣬ȱʡ֧ -//#define LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR +// 是否支持内存泄露检测,缺省不支持 +// #define LW_OOPC_SUPPORT_MEMORY_LEAK_DETECTOR -// Ƿֵ֧Ϣӡ(ڴͷŵϸϢȱʡرմӡ -//#define LW_OOPC_PRINT_DEBUG_INFO +// 是否支持调试信息打印(内存分配和释放的详细信息),缺省关闭打印 +// #define LW_OOPC_PRINT_DEBUG_INFO #ifdef LW_OOPC_USE_STDDEF_OFFSETOF #include @@ -47,7 +45,7 @@ #endif #ifdef LW_OOPC_USE_USER_DEFINED_OFFSETOF -// Щ֧֣ܲμٳ +// 有些环境可能不支持,不过,这种情形极少出现 #define LW_OOPC_OFFSETOF(s,m) (size_t)&(((s*)0)->m) #endif