【问题标题】:Variadic Macro for Multiple Inheritance多重继承的可变参数宏
【发布时间】:2012-09-15 19:16:46
【问题描述】:

我编写了一个宏,可以在类定义周围添加它,从而有效地完成它(防止子类化)。这种最终确定方法是一种相当常见的技术,在C++ FAQ 中有说明:

#define FINALIZE(NAME,...) \
    NAME##Finalizer {\
        private:\
            friend class NAME;\
            inline NAME##Finalizer(void) {}\
    };\
    class NAME : public virtual NAME##Finalizer, __VA_ARGS__

例如:

class FINALIZE(Fred) {};
//The above line evaluates to:
//  class FredFinalizer {
//      private:
//          friend class Fred;
//          inline FredFinalizer(void) {}
//  };
//  class Fred : public virtual FredFinalizer, {};

class George {};
class FINALIZE(Fred2, public George) {};
//The above line evaluates to:
//  class Fred2Finalizer {
//      private:
//          friend class Fred2;
//          inline Fred2Finalizer(void) {}
//  };
//  class Fred2 : public virtual Fred2Finalizer, public George {};

class Velma : public Fred { Velma(void) {} /*Note compile error*/ };
class Velma2 : public Fred2 { Velma2(void) {} /*Note compile error*/ };

这很好用。问题是我现在想要一种“禁用”宏的方法。那就是:

class FINALIZE(Fred) {};
//The above line evaluates to:
//  class Fred {};

class George {};
class FINALIZE(Fred2, public George) {};
//The above line evaluates to:
//  class Fred2 : public George {};

问题在于class Fred2 : public George {}; 与没有继承的情况(class Fred {};)冲突:在第一种情况下,必须始终有一个冒号,在第二种情况下,必须没有。请注意,启用宏时这不是问题,因为类always 继承自至少 NAME##Finalizer 类。

我怎样才能写一个宏来做到这一点?

【问题讨论】:

  • 是否有理由让解决方案成为宏?
  • 你会接受一个虚拟基类吗?
  • 这个问题并不重要,但如果这是您的最终目标(防止继承),您可能希望私有化虚拟基类。看来这将是您链接的描述中非常关键的部分。
  • @DeadMG 他这样做是为了防止一个类成为派生的基础,这是 Java 狂热者非常熟悉的东西。
  • CraigNelson,正确,尽管我反对隐含的想法,即我喜欢 Java。相反,除了 C#,我最讨厌现代语言了。 DeadMG,我一直在抱怨,因为用户愚蠢地继承了明确标记为“不继承自”的类。编译时解决方案是有序的。

标签: c++ inheritance macros


【解决方案1】:

我建议制作两个宏,一个用于准备终结器,一个用于使用:

#define PREP_FINALIZE(NAME) \
    class NAME##Finalizer {\
        private:\
            friend class NAME;\
            inline NAME##Finalizer() {}\
    }

#define FINALIZE(NAME) virtual NAME##Finalizer

所以在你的例子中:

PREP_FINALIZE(Fred);
class Fred : FINALIZE(Fred) {};

class George {};
PREP_FINALIZE(Fred2);
class Fred2 : FINALIZE(Fred2), public George {};

但更重要的是你忘记了将复制构造函数设为私有。没有它,你的方式很容易作弊:

// cheating :D
class Velma : public Fred, FINALIZE(Fred) { 
   Velma() : FredFinalizer(*(FredFinalizer*)0) {} /*Who said this is compiler error */ 
};

将终结器的复制构造函数设为私有。或者使用我的answer 来回答非常相似的问题。

对于 C++11,只需使用 final ;)

【讨论】:

  • 谢谢;出于美学原因,我试图避免制作两个宏。真的需要两个宏吗? +1 用于捕获复制构造函数。
  • 我相信单独的宏更容易。但是,您可以想到 FINALIZE: 用于没有基类的情况,而 FINALIZEM 用于具有基类的情况。仍然是两个宏,但对于每个类,您只使用一个。
  • 我找不到更好的解决方案,所以我们将继续使用它。谢谢,
猜你喜欢
  • 2023-04-10
  • 2014-05-15
  • 2016-06-20
  • 2015-06-01
  • 2019-04-25
  • 2018-01-13
  • 1970-01-01
  • 2012-08-26
  • 1970-01-01
相关资源
最近更新 更多