我通过使用Polymorphism (in C)中所述的虚拟表来利用C语言中的多态性,并且效果很好。
不幸的是,由于当前项目的限制,我无法在代码的某些部分中使用函数指针或对结构的引用。结果,我不能直接使用原始方法。
在上述方法中,基本“类/结构”具有指向虚拟表的成员。为了利用此指针,我决定将其替换为枚举,该枚举充当访问虚拟表的键。
它可以工作,但是我想知道是否是最好的解决方案。您能提出比我的建议更合适的替代方案吗?
/**
* This example shows a common approach to achive polymorphism in C and an
* alternative that does NOT include a reference to function pointer in the
* base
* class.
**/
#include<stdio.h>
// some functions to make use of polymorphism
void funBase1()
{
printf("base 1 \n");
}
void funBase2()
{
printf("base 2 \n");
}
void funDerived1()
{
printf("derived 1 \n");
}
void funDerived2()
{
printf("derived 2 \n");
}
// struct to host virtual tables
typedef struct vtable {
void (*method1)(void);
void (*method2)(void);
}sVtable;
// enumerate to access the virtual table
typedef enum {BASE, DERIVED} eTypes;
// global virtual table used for the alternative solution
const sVtable g_vtableBaseAlternative[] = {
{funBase1, funBase2},
{funDerived1, funDerived2}, };
// original approach that i cannot use
typedef struct base {
const sVtable* vtable;
int baseAttribute;
}sBase;
// alternative approach
typedef struct baseAlternative {
const eTypes vtable_key;
int baseAttribute;
}sBaseAlternative;
typedef struct derived {
sBase base;
int derivedAttribute;
}sDerived;
// original way to use
static inline void method1(sBase* base)
{
base->vtable->method1();
}
const sVtable* getVtable(const int key, const sVtable* vTableDic)
{
return &vTableDic[key];
}
// Alternative to get a reference to the virtual table
static inline void method1Aternative(sBaseAlternative* baseAlternative)
{
const sVtable* vtable;
vtable = getVtable(baseAlternative->vtable_key, g_vtableBaseAlternative);
printf("alternative version: ");
vtable->method1();
}
int main() {
const sVtable vtableBase[] = { {funBase1, funBase2} };
const sVtable vtableDerived[] = { {funDerived1, funDerived2} };
sBase base = {vtableBase, 0 };
sBase derived = {vtableDerived, 1 };
sBaseAlternative baseAlternative = {DERIVED, 1 };
method1(&base);
method1(&derived);
method1Aternative(&baseAlternative);
}
答案 0 :(得分:1)
我当前的项目不允许我使用函数指针或对结构的引用
您可以使用<div class="container">
<div class="row">
<p>Some text heree</p>
<h1>Title</h1>
<div class="col-md-4 col-xs-12">
<img src="https://www.dike.lib.ia.us/images/sample-1.jpg"class="img-responsive"/>
</div>
<p>Some text here </p>
<button>CTA</button>
</div>
</div>
数组(您喜欢的任何类型)来表示数据类型。例如,我倾向于使用T
数组对我的数据结构进行序列化和反序列化以进行Web传输...例如,假设您使用unsigned char
和sprintf
进行序列化和反序列化(您实际上不应该这样做,但是对于演示来说,它们是可以的)...代替sscanf
参数,使用struct
参数,然后使用{{ 1}}将该数据读取到局部变量,char *
对其进行修改...这涵盖了没有引用sscanf
的问题问题。
关于功能指针问题,您可以将所有功能合并为sprintf
所标记的...字符串形式的结构 ...这是一个简单的示例(尚未完成),涉及两个类的候选对象:一个长度前缀的字符串,该字符串使用两个字节进行编码C字符串行为的衍生的长度和种类,以及 C字符串的长度。
struct
C是一种图灵完整的编程语言,因此它当然可以用于模仿面向对象的多态性 ...,但是它在模仿过程性方面要好得多多态,甚至在某些情况下甚至是功能性多态 ...例如,您可以说switch
和enum { fubar_is_string, fubar_is_length_prefixed_string };
typedef unsigned char non_struct_str_class;
size_t non_struct_strlen(non_struct_str_class *fubar) {
size_t length = 0;
switch (fubar++[0]) {
case fubar_is_length_prefixed_string:
length = fubar++[0];
length <<= 8;
length += fubar++[0];
// carry through into the next case
// to support strings longer than 64KB
case fubar_is_string: if (!length)
length = strlen(fubar);
/* handle fubar as string */
}
return length;
}
使用的原始形式的参数多态类似于qsort
的含义(甚至更类似于bsearch
的惯用法)。
通过为所有标准浮点数类型提供通用的map
宏,您也可以将filter
用于有限的成功,例如作为the C11 standard does:
_Generic
如果您打算采用模仿的路线,则预处理器特别有用。...您可能会对Klemens的C11书感兴趣。
答案 1 :(得分:-2)
我正在利用C语言中的多态性
您当然不会。您仅创建它的假体。 IMO对C语言中的对象进行模拟是最糟糕的解决方案。如果您更喜欢OOP范例-请使用OO语言。在这种情况下,C ++。
回答您的问题-如果没有函数指针,您将无法(理性地)解决问题。
我不鼓励人们进行OOP尝试,例如使用过程语言进行编程。它通常导致可读性差,容易出错并且很难维护程序。
为任务和方法选择正确的工具(语言是工具)。
就像用刀代替螺丝刀一样。可以,但是螺丝刀肯定会更好。