【问题标题】:How to make base class's certain constructor be callable only by particular derived class(es)?如何使基类的某些构造函数只能由特定的派生类调用?
【发布时间】:2013-04-25 04:42:46
【问题描述】:
struct Base {
  Base (type1, type2, type3);
  Base (); // <--- should be invoked only by `Derived_2`
  virtual ~Base() = 0;  // an abstract class
};

上面说Base,我们有多个派生类:Derived_1Derived_2,...,Derived_N

在构造对象时,所有派生类都必须调用 Base(type1, type2, type3) 构造函数,但 Derived_2 除外,它在构造对象时应使用 Base()(默认构造函数)。

有没有办法(C++11 可以)有这样的规则?换句话说,如果Derived_2 以外的任何人尝试使用默认的无参数构造函数,那么编译器应该会报错。

编辑:对于那些询问设计问题的人,我同意这一点。这是我的看法。

  • 实际上,我根本不想要默认构造函数。全部 必须使用带参数的构造函数,它需要 runtime type1, type2, type3 形式的参数。
  • 现在,我看到继承层次结构中的几个类 对象将在main() 获取之前被全局实例化 执行。当然,这些都是特殊情况,必须娱乐 他们通过引入一个默认构造函数
  • 但是,这种治疗仅适用于 1 类或最多 2 类。休息一下 类必须保持调用带参数构造函数的规则。

我希望这能说明这个想法。

【问题讨论】:

  • 你想解决什么问题?
  • 需要了解其派生类型的基类并不是一个很好的设计。可能值得尝试重新设计它。
  • 如果派生类不能使用其基类中的公共方法,则看起来您正在破坏“is-a”关系。参见 Meyer 的 Effective C++,第 32 条:“公共继承意味着 is-a。适用于基类的所有内容也必须适用于派生类”
  • @KyleStrand,Julien,Peter,查看更新。
  • 不可能将gobal对象改为指针并在main()内动态分配并避免使用默认构造函数?

标签: c++ inheritance c++11 constructor


【解决方案1】:

我能想到的唯一方法是将Base 的默认构造函数声明为私有,并使Derived_2 成为Base 类的朋友,这样它就可以调用其默认构造函数。

但是,这种风格很糟糕,因为您的Base 类现在必须知道它的派生类之一。而且Dervived_2仍然可以调用3个参数的构造函数。

【讨论】:

    【解决方案2】:

    我将介绍另一个级别的推导:

            Base
             ^
             |
       +-----+------+
       |            |
    Derived2    BaseWithParams
                  ^         ^
                  |         |
               Derived1    DerivedN
    

    在基础中,您没有实现任何状态或默认状态(在我看来,拥有默认状态是有意义的,因为这就是 Derived2 应该这样做的原因)。

    struct Base
    {
        virtual ~Base() = 0;
    };
    struct Derived2 : public Base
    {
        Derived2() {}          // Do default initialization
        virtual ~Derived2() {} // Implement destructor so it's not pure virtual anymore
    };
    struct BaseWithCtor : public Base
    {
        BaseWithCtor(type1, type2, type3) {}
        // Do not implement destructor, leave the class abstract
    };
    

    【讨论】:

      【解决方案3】:

      将默认构造函数设为私有,并将 Derived_2 声明为友元:

      class Derived_2;
      
      class Base { 
          Base();
      public:
          Base(int, int, int);
          virtual ~Base() = 0;
          friend class Derived_2;
      };
      
      class Derived_1 : public Base { 
      public:
          Derived_1() : Base(1, 2, 3) {}
      };
      
      class Derived_1a : public Base { 
      public:
          Derived_1() {} // will fail: Base::Base() not accessible
      };
      
      
      class Derived_2 :public Base { 
      public:
         ~Derived_2() {}
      };
      

      【讨论】:

        【解决方案4】:

        当你编写派生类时,只有在第二个派生类中你应该调用默认的基构造函数,其余的你可以调用参数化构造函数。

              class derived1{             
                             derived1(): base(type1, type2, type3){}
        
                             };
        
               class derived2{
                              derived2(): base(){}
                              };
                class derived3{             
                             derived3(): base(type1, type2, type3){}
        
                             };
               class derived4{             
                             derived4(): base(type1, type2, type3){}
        
                             };
        

        `

        等等。对于其余的课程。另外......这是oop,您制作课程,以便您自己决定课程的行为。 因此,您只需确保在派生类的任何地方都没有显式调用基类的默认构造函数。 每次需要调用构造函数时,都在派生类中调用参数化构造函数,因为毕竟,您可以控制类的工作。

        【讨论】:

          猜你喜欢
          • 2016-07-19
          • 2018-07-16
          • 2015-05-28
          • 2018-07-21
          • 2015-08-18
          • 2014-03-26
          • 2011-09-27
          • 2012-12-24
          • 2011-05-03
          相关资源
          最近更新 更多