在C ++中使用#include宏来实现mixin模式是否好

时间:2018-06-28 09:52:15

标签: c++ design-patterns mixins

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

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

class Bird
  include Flyable
end

C ++不支持语言级别的混合功能,但是我们可以使用多重继承将代码插入派生类。但是此解决方案仍然存在其自身的问题,例如钻石继承,无法覆盖接口中的虚拟方法,无法访问“同级”模块中的成员等。

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

// in Flyable.h
public:
void fly() {
    // do something ...
}
float flySpeed;

在另一个文件中

// in Bird.h
class Bird {
#include "Flyable.h"
};

因此,所有成员变量和函数都将插入到Bird类。

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

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


修改

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


修改

我忘了解释代码的目的了。简而言之,这是在没有虚拟继承的情况下解决钻石问题的方法。据我了解,钻石问题的根本原因是滥用OOP。鸟“ is-a” FlyableAnimal,FlyableAnimal“ is-a”动物,鸟“ is-a”食肉动物,食肉动物“ is-a”动物。这种滥用的实际意图是代码重用,因此“ -able”比“ is-a”关系更好。和mixin可以带来“ -able”的关系。

在C ++中,mixin可以通过多重继承来实现。这是相当不错的,但是它将禁用多态。例如,我们具有带有纯虚函数的Animal接口,并且我们希望Bird实现它们。然后,我们不能使用多重继承将实现注入到Bird类。还有其他一些技术可以实现这一点,例如合成。但是我还没有看到像真正的mixin一样简单的解决方案。这就是我想到混入#include的原因。

1 个答案:

答案 0 :(得分:2)

  

此解决方案似乎没有明显的缺点。

缺点:

    后来加入您的项目的
  • devs在成为该项目的有效开发人员之前,需要学习更多的知识。仅当您必须在其他项目中维护其他人的非标准hack一段时间后,这才显而易见。

  • 这是意外的;这会引入错误,导致开发上的大量延迟(“嘿,我写了这个程序,但是没有编译。” /“是的,在那些文件中有一个奇怪的包含内容,您需要编写这样的代码代替”)。

  

代码可以很好地组织到不同的文件中。

整个行业都采用以下惯例来组织代码:

  • 域中的所有内容,单个API中的所有内容(无论这意味着单个类还是一组免费函数的集合),并且通常最多包含两个文件:一个用于声明,一个用于定义。

  • 在可行的情况下,仅保留标题为头

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

  • p>

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

  

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

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

这样做时您容易忘记的部分:

  • 在项目的整个生命周期中,您将不得不一遍又一遍地做出相同的决定。
  • 您将不得不让您的同事在项目的整个生命周期内(包括当您不再是项目的一部分时)一次又一次地做出相同的决定。使用标准解决方案很难做到这一点,更不用说使用非标准解决方案了。
  

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

总结(tldr):

  • 在整个项目过程中,您将不断增加维护工作量。

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

  • 任何遵循自己的直觉/所获得的经验的开发人员都希望在您的项目中看到其他内容(代码中WTF / sloc的增加)。

  • 这将在将来引起您团队的摩擦;至少如果您的团队中的开发人员关心代码的质量和易用性,那么至少会如此。