gpt4 book ai didi

c - 简单的结构继承和伪多态与严格的别名

转载 作者:太空狗 更新时间:2023-10-29 17:23:39 24 4
gpt4 key购买 nike

如果有人回答了我的问题,请不要告诉我使用C++。

因此,我正在使用C编写一个小型库,该库使用了一种面向对象的方法。我选择在C中使用两种主要的继承方法中比较少见的一种:将基本类型的成员复制到派生类型的开头。像这样的东西:

struct base {
int a;
int b;
char c;
};

struct derived {
int a;
int b;
char c;
unsigned int d;
void (*virtual_method)(int, char);
};

这种方法不如另一种方法(基类型的实例作为派生类型的第一个成员)流行,因为

从技术上来说,
  • 不能可靠地保证基础和派生结构的第一个公共(public)成员将具有相同的偏移量。但是,除了其中一个结构被打包而另一个结构没有打包的情况以外,它们在大多数(如果不是全部)已知编译器上具有相同的偏移量。
  • 这种方法最严重的缺陷:它违反了严格的别名。将指针转换为派生结构的指针为其基本类型,然后取消对该指针的引用在技术上是未定义的行为。

  • 但是,与其他方法相比,它也有其优点:
  • 不太详细:访问已继承的派生结构的成员与访问未继承的成员相同,而不是强制转换为基本类型,然后访问所需的成员。
  • 这实际上是真正的继承而不是组成;
  • 与其他方法一样容易实现,尽管可能需要一点预处理器滥用。
  • 我们可以得到实际的多重继承的半生半熟的形式,在这里我们可以从几种基本类型继承,但是只能转换为其中一种。

  • 我一直在研究使我的库编译并与使用严格别名(例如 gcc )的编译器正确工作的可能性,而无需用户手动将其关闭。这是我研究过的可能性:
  • 联盟。令人遗憾的是,出于以下几个原因,这些是不可以的:
  • Verbosity回来了!要遵循通过 union 访问2个结构的第一个公共(public)成员的标准规则,必须(从C99开始)明确使用 union 来访问第一个公共(public)成员。我们需要特殊的语法来访问 union 中每种类型的成员!
  • 空间。考虑一个继承层次结构。我们希望能够从其每个派生类型强制转换为该类型。我们想针对每种类型做到这一点。我看到的唯一可行的 union 雇用解决方案是整个层次结构的 union ,必须将其用于将派生类型的实例转换为基本类型。并且它必须与整个层次结构中最派生的类型一样大...
  • 使用memcpy而不是直接取消引用(例如here)。这看起来是一个不错的解决方案。但是,函数调用会产生开销,是的,也是冗长的。据我了解,也可以通过将指向结构的指针转换为指向memcpy的指针,然后取消引用char的方式来手动完成操作,如下所示:(member_type)(*((char*)(&struct_pointer->member))) = new_value; Gah,又是冗长。好吧,这可以用宏包装。但是,如果我们将指针转换为不兼容类型的指针,然后将其转换为char*并取消引用,那仍然可行吗?像这样:(member_type)(*((char*)(&((struct incompatible_type*)struct_pointer)->member))) = new_value;
  • 声明所有要转换为volatile的类型的实例。我想知道为什么这种情况不会经常出现。据我所知,volatile用来告诉编译器指针所指向的内存可能会意外更改,因此基于指向性内存段将不会更改的假设取消优化,这是导致错误的原因。所有严格混叠的问题。当然,这仍然是不确定的行为。但是对于“骇客地”禁用某些类型的某些实例的严格别名优化,这不是可行的跨平台解决方案吗?

  • 除了上述问题,还有两个:
  • 我上面说的是错误的吗?
  • 我错过了一些对我有帮助的东西吗?
  • 最佳答案

    我认为您关于通过char*进行强制转换的想法不正确。
    规则是:

    An object shall have its stored value accessed only by an lvalue expression that has one of the following types



    表达式的子表达式兼容,但整体表达式不兼容。

    我认为唯一现实的方法是合成:
    struct base {
    int a;
    int b;
    char c;

    void (*virtual_method)(base*/*this*/,int, char);

    };

    struct derived {
    struct base;
    unsigned int d;
    };

    我意识到,这是实现继承的一种不吸引人的方法。

    PS:我没有将您的虚拟成员函数指针放在派生类中。它需要可以从 base进行访问,因此需要在那里声明(假设 basederived都存在一个多态函数)。
    我还添加了一个 this参数,使模型更加丰富。

    关于c - 简单的结构继承和伪多态与严格的别名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27980925/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com