Compare commits

...

14 Commits

Author SHA1 Message Date
b88995b0bd 感觉得学习一下优秀的代码框架了。我尝试了很多,但现在想不到好的办法了。 2024-09-01 18:48:20 +08:00
42d305eabe container_of是谁发明的,真是个天才!!! 2024-09-01 17:38:44 +08:00
7f42d43cd2 修改工程结构后,测试可以。 2024-09-01 17:19:59 +08:00
a283d3bf14 修改cmake结构,方便后续调试 2024-09-01 17:05:05 +08:00
c1f45b94a4 多态测试通过 2024-09-01 16:54:38 +08:00
fd35e92c42 shape也修改成指针,但最后一句代码还存在问题 2024-09-01 16:28:49 +08:00
5975890154 shape_area函数访问孙子测试通过 2024-09-01 15:48:37 +08:00
d28aec06ca 多态实现的好奇怪,也勉强能用 2024-09-01 14:50:08 +08:00
5d6d031a3a C语言可以实现多态,但必须保证子类和父类相同的元素放在结构体最前面,且必须一模一样的排序。 2024-09-01 13:36:12 +08:00
2aca923437 修改this为pthis,防止在cpp上编译不通过(和关键字冲突) 2024-09-01 13:15:47 +08:00
52155db7e8 实现了多态,但是只能单继承,且父类必须放在子类最开头。 2024-09-01 04:00:56 +08:00
7021105e64 如果只是这样实现,那么无法多态。即给父类赋值子类,然后调用父类,实测还是调用的父类接口。因此添加虚函数表 2024-09-01 03:22:37 +08:00
196c331520 c语言实现继承 2024-09-01 02:46:08 +08:00
5f54a63d78 C语言实现面向对象 2024-09-01 02:07:04 +08:00
20 changed files with 491 additions and 222 deletions

View File

@ -1,69 +1,14 @@
# 0. cmake 最低版本号要求
cmake_minimum_required(VERSION 3.8)
# 0. 项目信息
project(demo)
# 2. 添加当前路径
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 2. 配置项目
option(USE_DEMO "use demo application interface" ON)
set(VERSION "1.0")
# 2. 配置文件
configure_file(
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# 2. 配置条件
if(USE_DEMO)
# include_directories(.)
# else()
# pass
endif(USE_DEMO)
# 0. 查找当前目录下的所有文件并将名称保存在DIR_SRC中
aux_source_directory(. DIR_SRC)
# 1. 添加子目录
add_subdirectory(src)
# 1. 添加头文件路径
include_directories(src)
# 0. 指定生成目标
add_executable(demo ${DIR_SRC})
# 1. 添加链接库
# 1.A 如果是动态库修改了安装路径之后exe就找不到了怎么破
# link_directories(${PROJECT_SOURCE_DIR}/lib)
# target_link_libraries(demo list_d)
# 1.B 静态库
target_link_libraries(demo list)
# 3. 配置安装路径
set(CMAKE_INSTALL_PREFIX "./release")
install(TARGETS demo DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"
DESTINATION include)
# 4. 启用测试
enable_testing()
# 测试程序是否成功运行
add_test (NAME test_demo COMMAND demo 1 2 3 5 8)
# 5. 支持GDB
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
#
# 构建一个 CPack 安装包windows还得添加打包工具
#
# include (InstallRequiredSystemLibraries)
# set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
# set (CPACK_PACKAGE_VERSION_MAJOR "${VERSION}")
# include (CPack)
include_directories(library)
add_subdirectory(library)
add_subdirectory(src)

View File

@ -1,36 +0,0 @@
# cmake_demo
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

View File

@ -1,39 +1,15 @@
# cmake_demo
#### 介绍
{**以下是 Gitee 平台说明,您可以替换此简介**
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN。专为开发者提供稳定、高效、安全的云端软件开发协作平台
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
## CMAKE
#### 软件架构
软件架构说明
## 多态
### 多态的本质
同样的接口,可以即实现父类的功能,也可以实现子类的功能。主要看传参的类型。
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
#### 使用说明
1. xxxx
2. xxxx
3. xxxx
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
#### 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
C语言实现思路
因为语法不支持,因此采用特殊的方式来实现。
| 类型 | 实现方式 | 弊端| 问题举例|
| --- | --- | --- | --- |
| 匿名结构体 | 指针 | 多重继承,成员可能冲突 | B->A, C->A, D->B,D->C|
| 虚函数表 | 指针 | 子类父类必须将虚表放在结构体最开头,且不支持多继承下的多态 | |
| 虚函数多参数 | 指针 | 继承的父类无顺序强制要求,且可以多继承。但类方法参数变多。多继承需要人为注意是调用了其他类还是继承了其他类 | |

View File

@ -1,2 +0,0 @@
#cmakedefine USE_DEMO
#cmakedefine VERSION "@VERSION@"

13
library/CMakelists.txt Normal file
View File

@ -0,0 +1,13 @@
project(class)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 当前目录下的文件 -> 写入变量
aux_source_directory(. SRCS)
# 生成链接库
add_library(${PROJECT_NAME} SHARED ${SRCS})
# 配置安装库
install (TARGETS ${PROJECT_NAME} DESTINATION bin)

57
library/circle.c Normal file
View File

@ -0,0 +1,57 @@
#include "circle.h"
double circle_area(void *self, void *parent)
{
double area = 0;
struct _circle *pthis = (struct _circle *)parent;
area = pthis->shape->vtb.area(self, NULL);
return area;
}
void circle_draw(void *self, void *parent)
{
struct _circle *pthis = (struct _circle *)parent;
pthis->shape->vtb.draw(self, NULL);
}
double _circle_area(void *self, void *parent)
{
struct _circle *pthis = (struct _circle *)self;
double area = 3.14 * pthis->radius * pthis->radius;
printf("circle area = %0.2f\n", area);
return area;
}
void _circle_draw(void *self, void *parent)
{
printf("circle draw\n");
}
struct _circle *circle_new(double radius)
{
// super
static struct _virtual_table vtb = {
.area = (double (*)(void *self, void *parent))_circle_area,
.draw = (void (*)(void *self, void *parent))_circle_draw,
};
struct _shape *shape = shape_new();
if (shape == NULL)
{
return NULL;
}
shape->vtb = vtb;
// self
struct _circle *circle = calloc(1, sizeof(struct _circle));
if (circle == NULL)
{
return NULL;
}
circle->radius = radius;
// set parent
circle->shape = shape;
return circle;
}

28
library/circle.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef _CIRCLE_H_
#define _CIRCLE_H_
#include "common.h"
#include "shape.h"
struct _circle
{
int invalid;
// super
struct _shape *shape;
// attribute
double radius;
// method
// void (*area)(void *self);
// void (*draw)(void *self);
};
struct _circle *circle_new(double radius);
double circle_area(void *self, void *parent);
void circle_draw(void *self, void *parent);
#endif

24
library/common.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>
// [warring] offsetof is redefined in stddef.h
//
// #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
// #define container_of(ptr, type, member) ({ \
// const typeof( ((type *)0)->member ) *__mptr = (ptr); \
// (type *)( (char *)__mptr - offsetof(type,member) );})
#define _offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - _offsetof(type,member) );})
#endif

69
library/copper.c Normal file
View File

@ -0,0 +1,69 @@
#include "copper.h"
double copper_cash_area(struct _copper_cash *self, void *parent)
{
// 如果用的继承,那么就不能直接调用父类的虚接口,实现自己。
// 因为父类虚接口,是自己实现的。这样相当于自己调用自己。导致卡死。
// double circle_area = self->circle->shape->vtb.area(self->circle, self->circle);
// double rect_area = self->rect->shape->vtb.area(self->rect, self->rect);
double circle_area = 3.14 * self->circle->radius * self->circle->radius;
double rect_area = self->rect->width * self->rect->height;
double area = circle_area - rect_area;
printf("copper cash area = %0.2f\n", circle_area - rect_area);
return area;
}
void copper_cash_draw(struct _copper_cash *self, void *parent)
{
printf("copper cash draw\n");
}
struct _copper_cash *copper_cash_new(double width, double height, double radius)
{
// super
static struct _virtual_table vtb = {
.area = (double (*)(void *self, void *parent))copper_cash_area,
.draw = (void (*)(void *self, void *parent))copper_cash_draw,
};
struct _shape *shape = shape_new();
if (shape == NULL)
{
return NULL;
}
shape->vtb = vtb;
struct _rect *rect = rect_new(width, height);
if(rect == NULL)
{
return NULL;
}
rect->shape = shape;
struct _circle *circle = circle_new(radius);
if (circle == NULL)
{
return NULL;
}
circle->shape = shape;
// self
struct _copper_cash *cc = calloc(1, sizeof(struct _copper_cash));
if (cc == NULL)
{
return NULL;
}
cc->self = cc;
cc->price = 100;
// set parent
cc->shape = shape;
cc->rect = rect;
cc->circle = circle;
return cc;
}

26
library/copper.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _COPPER_CASH_H_
#define _COPPER_CASH_H_
#include "common.h"
#include "shape.h"
#include "rect.h"
#include "circle.h"
struct _copper_cash
{
struct _copper_cash *self;
struct _shape *shape;
struct _rect *rect;
struct _circle *circle;
double price;
};
struct _copper_cash *copper_cash_new(double width, double height, double radius);
double copper_cash_area(struct _copper_cash *self, void *parent);
void copper_cash_draw(struct _copper_cash *self, void *parent);
#endif

61
library/rect.c Normal file
View File

@ -0,0 +1,61 @@
#include "rect.h"
double rect_area(void *self, void *parent)
{
double area = 0;
struct _rect *pthis = (struct _rect *)parent;
area = pthis->shape->vtb.area(self, NULL);
return area;
}
void rect_draw(void *self, void *parent)
{
struct _rect *pthis = (struct _rect *)parent;
pthis->shape->vtb.draw(self, NULL);
}
double _rect_area(void *self, void *parent)
{
struct _rect *pthis = (struct _rect *)self;
double area = pthis->width * pthis->height;
printf("rect area = %0.2f\n", area);
return area;
}
void _rect_draw(void *self, void *parent)
{
printf("rect draw\n");
}
struct _rect *rect_new(double width, double height)
{
// super
static struct _virtual_table vtb = {
.area = (double (*)(void *self, void *parent))_rect_area,
.draw = (void (*)(void *self, void *parent))_rect_draw,
};
struct _shape *shape = shape_new();
if (shape == NULL)
{
return NULL;
}
shape->vtb = vtb;
// self
struct _rect *rect = calloc(1, sizeof(struct _rect));
if (rect == NULL)
{
return NULL;
}
rect->self = rect;
rect->width = width;
rect->height = height;
// set parent
rect->shape = shape;
return rect;
}

25
library/rect.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef _RECT_H_
#define _RECT_H_
#include "common.h"
#include "shape.h"
struct _rect
{
// int invalid;
struct _rect *self;
// super
struct _shape *shape;
// attribute
double width, height;
};
struct _rect *rect_new(double width, double height);
double rect_area(void *self, void *parent);
void rect_draw(void *self, void *parent);
#endif

77
library/shape.c Normal file
View File

@ -0,0 +1,77 @@
#include "shape.h"
double virtual_area(void *self, void *parent)
{
ASSERT_CALL_VIRTUAL_METHOD();
}
void virtual_draw(void *self, void *parent)
{
ASSERT_CALL_VIRTUAL_METHOD();
}
struct _virtual_table *virtual_new(void)
{
struct _virtual_table *vtb = calloc(1, sizeof(struct _virtual_table));
if (vtb == NULL)
{
return NULL;
}
vtb->area = virtual_area;
vtb->draw = virtual_draw;
return vtb;
}
double shape_area(void *self, void *parent)
{
double area = 0;
struct _shape *pthis = (struct _shape *)parent;
area = pthis->vtb.area(self, NULL);
return area;
}
void shape_draw(void *self, void *parent)
{
struct _shape *pthis = (struct _shape *)parent;
pthis->vtb.draw(self, NULL);
}
PRIVATE double _shape_area(void *self, void *parent)
{
ASSERT_CALL_VIRTUAL_METHOD();
}
PRIVATE void _shape_draw(void *self, void *parent)
{
ASSERT_CALL_VIRTUAL_METHOD();
}
struct _shape *shape_new(void)
{
struct _shape *shape = calloc(1, sizeof(struct _shape));
if(shape == NULL)
{
return NULL;
}
shape->self = shape;
static struct _virtual_table vtb = {
.area = (double (*)(void *self, void *parent))_shape_area,
.draw = (void (*)(void *self, void *parent))_shape_draw
};
shape->vtb = vtb;
return shape;
}
#if 0
void shape_free(struct _shape * self)
{
if (self != NULL)
{
free(self);
}
}
#endif

32
library/shape.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef _SHAPE_H_
#define _SHAPE_H_
#include "common.h"
#define VIRTUAL
#define PRIVATE static
#define ASSERT_CALL_VIRTUAL_METHOD() assert(!("can't call abstract method"))
struct _virtual_table
{
VIRTUAL double (*area)(void *self, void *parent);
VIRTUAL void (*draw)(void *self, void *parent);
};
struct _shape
{
struct _shape *self;
struct _virtual_table vtb;
};
struct _shape *shape_new(void);
double shape_area(void *self, void *parent);
void shape_draw(void *self, void *parent);
#endif

4
mk.bat
View File

@ -1,6 +1,8 @@
@REM D:\Lang\cmake-3.27.5-windows-x86_64\bin\cmake.EXE --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_C_COMPILER:FILEPATH=D:\Software\mingw64\bin\gcc.exe -DCMAKE_CXX_COMPILER:FILEPATH=D:\Software\mingw64\bin\g++.exe -SF:/OpenDemo/1_vsc_cmake -Bf:/OpenDemo/1_vsc_cmake/build -G "MinGW Makefiles"
@REM cmake -Bbuild -G "Visual Studio 17 2022"
del ".\\build\\release\\bin\\demo.exe"
cmake -B build -G "MinGW Makefiles"
make -C build
@ -9,3 +11,5 @@ make -C build test
@REM cpack -C ./build/CPackConfig.cmake
@REM cpack -C ./build/CPackSourceConfig.cmake
".\\build\\release\\bin\\demo.exe"

View File

@ -1,17 +1,14 @@
# 当前目录下的文件 -> 写入变量
aux_source_directory(. DIR_LIB_SRC)
project(demo)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 生成链接库
# add_library(list ${DIR_LIB_SRC})
add_library(list STATIC ${DIR_LIB_SRC})
add_library(list_d SHARED ${DIR_LIB_SRC})
aux_source_directory(. SRCS)
# 配置安装头文件
install (FILES list.h DESTINATION include)
# 配置安装库
install (TARGETS list DESTINATION bin)
add_executable(${PROJECT_NAME} ${SRCS})
# install (TARGETS list_d DESTINATION bin)
# install (TARGETS list_d DESTINATION lib)
target_link_libraries(
${PROJECT_NAME}
class
)
install(TARGETS ${PROJECT_NAME} DESTINATION bin)

View File

@ -1,58 +0,0 @@
#include "list.h"
void list_init(struct list_t *list)
{
list->data = 0;
list->next = NULL;
}
void list_add(struct list_t *list, uint8_t data)
{
struct list_t *p = NULL;
p = list;
while (p->next != NULL)
{
p = p->next;
if (p->data == data)
{
return;
}
}
p->next = (struct list_t *)malloc(sizeof(struct list_t));
p->next->data = data;
p->next->next = NULL;
return;
}
void list_print(struct list_t *list)
{
struct list_t *p = NULL;
p = list;
while (p->next != NULL)
{
printf("%02d ", p->data);
p = p->next;
if (p->next == NULL)
{
printf("%02d\n", p->data);
break;
}
}
}
void list_free(struct list_t *list)
{
struct list_t *p = NULL;
p = list;
while (p->next != NULL)
{
p = p->next;
free(p->next);
p->next = NULL;
if (p->next == NULL)
{
break;
}
}
}

View File

@ -1,20 +0,0 @@
#ifndef _LIST_H_
#define _LIST_H_
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct list_t
{
uint8_t data;
struct list_t *next;
} list_t;
void list_init(struct list_t *list);
void list_add(struct list_t *list, uint8_t data);
void list_print(struct list_t *list);
void list_free(struct list_t *list);
#endif

51
src/main.c Normal file
View File

@ -0,0 +1,51 @@
#include "shape.h"
#include "rect.h"
#include "circle.h"
#include "copper.h"
int main(int argc, char *argv[])
{
struct _rect *rect = rect_new(4, 5);
rect_area(rect, rect);
rect_draw(rect, rect);
struct _circle *circle = circle_new(3);
circle_area(circle, circle);
circle_draw(circle, circle);
printf("----- rect & circle -----\n");
shape_area(rect, rect->shape);
shape_draw(rect, rect->shape);
shape_area(circle, circle->shape);
shape_draw(circle, circle->shape);
printf("----- [2] rect & circle -----\n");
struct _rect *rect2 = (struct _rect *)rect_new(2, 3);
shape_area(rect2, rect2->shape);
shape_draw(rect2, rect2->shape);
struct _circle *circle2 = (struct _circle *)circle_new(1);
shape_area(circle2, circle->shape);
shape_draw(circle2, circle->shape);
// printf("----- [2] shape -----\n");
// struct _shape *shape = shape_new();
// shape_area(shape, shape);
// shape_draw(shape, shape);
printf("----- copper_cash -----\n");
struct _copper_cash *cc = copper_cash_new(2, 2, 4);
shape_area(cc, cc->shape);
shape_draw(cc, cc->shape);
printf("----- [2] copper_cash -----\n");
rect_area(cc, cc->rect);
rect_draw(cc, cc->rect);
circle_area(cc, cc->circle);
circle_draw(cc, cc->circle);
return 0;
}