C++ 在C+中使用#include宏实现mixin模式好吗+;

C++ 在C+中使用#include宏实现mixin模式好吗+;,c++,design-patterns,mixins,C++,Design Patterns,Mixins,正如我们所知,mixin是一种将某些行为“插入”到另一个类的设计模式。例如,在Ruby中,我们可以编写如下代码 module Flyable def fly puts "I'm flying"; end end class Bird include Flyable end C++不支持语言级别的mixin,但我们可以使用多重继承将代码插入派生类。但该解决方案仍然存在自身的问题,如菱形继承、无法覆盖接口中的虚拟方法、无法从“同级”模块访问成员等 后来我发现我可以使用#inc

正如我们所知,mixin是一种将某些行为“插入”到另一个类的设计模式。例如,在Ruby中,我们可以编写如下代码

module Flyable
  def fly
    puts "I'm flying";
  end
end

class Bird
  include Flyable
end
C++不支持语言级别的mixin,但我们可以使用多重继承将代码插入派生类。但该解决方案仍然存在自身的问题,如菱形继承、无法覆盖接口中的虚拟方法、无法从“同级”模块访问成员等

后来我发现我可以使用#include宏将代码段插入到类定义中,以实现mixin:

// in Flyable.h
public:
void fly() {
    // do something ...
}
float flySpeed;
在另一个文件中

// in Bird.h
class Bird {
#include "Flyable.h"
};
所以所有的成员变量和函数都被插入到Bird类中

这种解决方案似乎没有明显的缺点。代码被很好地组织到不同的文件中。精心设计的模块可以避免可能的名称冲突,而无需重叠的功能/规则

但我仍然担心有些问题我还没有看到。这种混音有什么问题吗


编辑

我知道使用#include inside类定义很奇怪。但它确实解决了问题。如果它真的在项目中使用,程序员可以习惯它。所以我想知道,我们应该避免这样的代码,有什么实际的原因吗?不仅仅是它丑陋、怪异或者没有人这样写


编辑

我忘了解释代码的用途。简单地说,这是为了解决钻石问题而没有虚拟继承。据我所知,钻石问题的根本原因是OOP的滥用。“鸟”是“可飞的动物,可飞的动物”是“动物,鸟”是“食肉动物,食肉动物”是“动物”。这种滥用的实际意图是代码重用,因此与“is-a”关系相比,“-able”更好。而mixin可以带来“有能力”的关系

在C++中,MIXIN可以通过多重继承来实现。这很好,但它将禁用多态性。例如,我们有纯虚拟功能的动物接口,我们希望Bird实现它们。然后我们不能使用多重继承将实现注入Bird类。还有其他一些技巧可以实现这一点,比如构图。但我还没有看到任何解决方案像真正的混合一样简单。这就是我考虑加入的原因

这种解决方案似乎没有明显的缺点

缺点:

  • 稍后加入您的项目的开发人员在成为项目中的有效开发人员之前,将有更多需要学习的内容。只有在您不得不在其他项目中维护其他人的非标准黑客行为一段时间后,这一点才明显

  • 这是出乎意料的;这将引入bug,导致开发过程中的大量延迟(“嘿,我写了这个,但它没有编译。”/“是的,这些文件中有一个奇怪的include,你需要像这样编写代码”)

代码被很好地组织到不同的文件中

整个行业在组织代码时采用以下约定:

  • 一个域中的所有内容,在单个API中(无论是指单个类还是单个自由函数集合),通常最多在两个文件中:一个用于声明,一个用于定义

  • 在可行的情况下,只保留标题

  • 如果不可能,请在.impl或_impl类中编写实现,并将其包含在头中(这不是事实上的标准,但您可以看到它与模板化代码一起使用)

您的解决方案明显不同于此(也就是说,显然没有很好地组织到不同的文件中)

精心设计的模块可以避免可能的名称冲突,而无需重叠的功能/规则

当人们做出这种区分时(“是的,代码是可维护的,您只需格外小心”),他们会想象您看到问题,应用解决方案,提交,问题就解决了

进行此操作时,您往往会忘记以下部分:

  • 在项目的整个生命周期中,您必须一次又一次地做出相同的决定
  • 在项目的整个生命周期中(包括当你不再是项目的一部分时,你自己),你必须让你的同事做出同样的决定。这很难,用标准溶液,更不用说非标准溶液了
但我仍然担心有些问题我还没有看到。这种混音有什么问题吗

总结一下(tldr):

  • 在项目期间,您将需要不断增加维护工作

  • 这对任何新员工来说都是违反直觉的,并且会增加其他人加入您的项目的成本

  • 任何遵循直觉/经验的开发人员都希望在项目中看到其他东西(代码中增加WTF/sloc)

  • 这将在你的团队中造成摩擦,在未来;如果您的团队中有关心代码质量和易用性的开发人员,至少会这样


行为的混合应该很少会导致菱形模式继承问题。如果你这样做了,那么我会说你的设计(或它的实现)是有缺陷的。至于你的“解决方案”,从软件工程的角度来看,它真的很糟糕。它使代码更难阅读,更难维护。使用预处理器生成代码并非闻所未闻。但不要使用include指令。这是独特的。当其他开发者看到这一点时,他们的眉毛会直勾勾。一个
MAKE_FLYABLE()
宏在WTF/秒方面会好得多。@Someprogrammerdude是的,使用继承来混合不会以菱形模式结束,但仍然有其他问题。我知道使用include似乎很糟糕,但我说不出原因。你能解释一下吗?事实上你和我合作了吗