【问题标题】:Calling protected ctor of inheriting class from within static template method of base class fails从基类的静态模板方法中调用继承类的受保护 ctor 失败
【发布时间】:2015-02-16 04:51:48
【问题描述】:

我有一个组件类,它定义了一个静态模板方法,一般来说应该如何创建 Component

class Component {
protected:
    uint32_t id;

    Component(uint32_t id) :
            id(id) {
    }

    template<typename T, uint32_t C>
    static T* createComponent() {
        // content here not relevant
        return new T(someParameter);
    }

};

然后有一个实现,例如Button。这个类的构造函数不能直接使用,而是有一个静态方法调用Component::createComponent模板函数。

class Button: public Component {
protected:
    Button(uint32_t id) :
            Component(id) {
    }
public:
    static Button* create();
};

实现看起来像这样,传递要实例化的类型和创建时使用的常量:

Button* Button::create() {
    return createComponent<Button, UI_COMPONENT_BUTTON>();
}

现在的问题是,编译器抱怨 “错误:'Button::Button(uint32_t)' is protected”。据我了解,这个构造函数调用应该没问题,因为Button 扩展了Component,但这似乎是一个问题。

我该如何解决这个问题?

【问题讨论】:

  • 你标题的复杂性让我崩溃了,但这是个好问题。
  • 我无法想象一个更简单的描述基本问题的方法:D
  • 好吧,你的构造函数没有做任何'Create'方法不能做的事情,所以不要使用任何Ctor?
  • 问题是还有一个Window类不使用createComponent函数,虽然我还是想强制它把id传给构造函数。但是,是的,你是对的,我可以将该逻辑添加到模板函数中。 :) 谢谢!

标签: c++ templates inheritance protected


【解决方案1】:

由于您的create() 函数将无法处理进一步继承的类,您可以利用这一点,创建一个Button,而是创建一个泛型派生的、受保护的、可以访问您的 protected 构造函数的派生类:

class Component {
    uint32_t id;
    template <typename T>
    struct Concrete: T {
        Concrete(uint32_t id): T(id) {}
    };
protected:
    Component(uint32_t id) :
        id(id) {
    }

    template<typename T, uint32_t C>
    static T* createComponent() {
        // content here not relevant
        return new Concrete<T>(C);
    }
};

class Button:
    public Component {
protected:
    Button(uint32_t id): Component(id) {}
public:
    static Button* create() {
         return createComponent<Button, UI_COMPONENT_BUTTON>();
    }
};

【讨论】:

  • 哇,很棒的解决方案!非常感谢。
  • 是的,Base::createComponent() 当使用 ConcreteButton&lt;T&gt; 调用时,确实会返回 Concrete&lt;Button&gt;*。然而。用户调用Button::create(),返回其基类:Button*
  • 想一想,Base::createComponent() 实际上可以使用Button 并在内部创建一个ConcreteButton&lt;T&gt; - 这样派生类甚至不需要知道这个辅助类和它可以在Base 中设为私有!我会相应地更新代码。
  • 您还可以在createComponent 中实例化Concrete&lt;T&gt; 以使其更容易:)
  • 评论比赛条件 :D 干得好,没想到 :)
【解决方案2】:

Button 构造函数的访问说明符是受保护的,这意味着它只能被从 Button 派生的类访问。如果您希望您的代码正常工作,那么您必须公开该构造函数。

【讨论】:

  • 谢谢,我认为继承仍然可以向上工作。找到了另一个同样有效的解决方案:将friend class Component; 添加到Button 的类主体中。
  • 正确。 protected 不授予对基类的访问权限,仅授予派生类...
  • @maxdev:仅作记录:您绝对必须使构造函数public 并且根据您所写的内容,您可能不想这样做。虽然访问权限不能向上工作,但您可以通过由基控制的派生类使用简单的委托来处理 protected 构造函数(例如,参见我的答案)。
【解决方案3】:

“Button”扩展了“Component”,因此“Button”可以访问“Component”的受保护成员,但“Component”不知道“Button”,因此无法访问它的受保护成员。

【讨论】:

  • 不知道有点含糊,我可以让全班都知道。
猜你喜欢
  • 2014-01-30
  • 2010-09-14
  • 1970-01-01
  • 2018-08-23
  • 2016-03-17
  • 2019-10-03
  • 2014-06-19
  • 2011-07-23
  • 2011-10-22
相关资源
最近更新 更多