【问题标题】:What are practical uses of a protected constructor?受保护构造函数的实际用途是什么?
【发布时间】:2010-11-06 15:10:35
【问题描述】:

为什么有人会声明构造函数受保护?我知道构造函数被声明为私有是为了不允许在堆栈上创建它们。

【问题讨论】:

    标签: c++ constructor protected


    【解决方案1】:

    您可以使用它来限制可以创建它的类,例如:

    class Level
    {
    private:
    
     Level();
     ~Level();
    
     friend class LevelManager;
    };
    

    唯一可以创建其实例的类是 LevelManager 类,因此您将始终知道 Level 实例是在 LevelManager 中创建的。

    【讨论】:

    • 虽然是这样,但这是一个私有构造函数,不受保护。
    【解决方案2】:

    protected构造函数的一个用途是实现CRTP模式,见下面的代码:

    #include <iostream>
    #include <assert.h>
    
    template <class T>
    class ComparableMixin {
    public:
        bool operator !=(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) == static_cast<T&>(other));
        }
        bool operator <(ComparableMixin &other) {
            return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
        }
        bool operator >(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
        }
        bool operator >=(ComparableMixin &other) {
            return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
        }
    protected:
        ComparableMixin() {}
    };
    
    class Integer: public ComparableMixin<Integer> {
    public:
     Integer(int i) {
         this->i = i;
     }
     int i;
     bool operator <=(Integer &other) {
         return (this->i <= other.i);
     }
     bool operator ==(Integer &other) {
         return (this->i == other.i);
     }
    };
    int main() {
    
        Integer i(0) ;
        Integer j(1) ;
        //ComparableMixin<Integer> c; //compilation error!
        assert (i < j );
        assert (i != j);
        assert (j >  i);
        assert (j >= i);
    
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      当类的方法都不是纯虚拟的时,可以使用受保护的构造函数使类有效抽象。

      它在 C++ 意义上不是很抽象,因为友元类仍然可以使用它而无需覆盖,但是你必须声明它们。

      【讨论】:

        【解决方案4】:

        对于有副作用的工厂方法。

        class mine {
        
          private:
            mine () {};
        
          protected:
            mine(int id) : m_id(id) {};
        
           int m_id;
           static int m_count;
        
          public:
            static mine* CreateOneOfMe() {
                 return mine(m_count++);
            }
        
            int GetId() { return m_id; }
        
         };
        

        这会创建类的实例并保证它们中的每一个都有一个唯一的递增整数 id。注意,如果你要使用的构造函数不是默认的,你也必须隐藏默认的。

        【讨论】:

        • 你也可以不声明默认构造函数,它就不会存在。
        【解决方案5】:

        当存在无法单独由构造函数保证的构造要求时,非公共构造函数很有用。例如,如果需要在构造函数之后立即调用初始化方法,或者如果对象需要向某个容器/管理器对象注册自身,则必须在构造函数之外完成。通过限制对构造函数的访问并仅提供工厂方法,您可以确保用户接收到的任何实例都将履行其所有保证。这也常用于实现 Singleton,这实际上只是该类做出的另一个保证(即只有一个实例)。

        使构造函数受保护而不是私有的原因与使任何其他方法或字段受保护而不是私有的原因相同:以便它可以被子级继承。也许您希望基类中有一个公共的、非虚拟的工厂方法,它返回对派生类实例的引用;派生类显然想要访问父构造函数,但您仍然不想在工厂之外创建它们。

        【讨论】:

          【解决方案6】:

          当一个类是(打算作为)一个抽象类时,一个受保护的构造函数是完全正确的。在这种情况下,您不希望从类中实例化对象,而只是使用它来继承。

          还有其他用例,例如某些构造参数集应仅限于派生类。

          【讨论】:

          • +1 但不一定是抽象类。但情况往往如此。
          • 将函数声明为纯虚函数不足以定义基类吗?或者上面是在没有纯虚函数的情况下。这种抽象类的派生类的创建事件是什么?
          • 尼尔,我不是在这里发动语言战争,只是回答了受保护的 ctor 有什么好处。但是你应该能够理解抽象类有一个设计级别的概念,它与 C++/Delphi 的定义不同。
          • 表示类是抽象的规范方法是使析构函数纯虚拟。但我倾向于使构造函数也受到保护,既是为了“腰带和吊带”保护,也是为了让客户清楚他们不能直接实例化类的对象。
          • 结合答案和cmets,这个答案我很能接受。
          【解决方案7】:

          受保护的构造函数意味着只有派生成员才能使用该构造函数构造类的实例(和派生实例)。这听起来有点鸡和蛋,但在实现类工厂时有时很有用。

          【讨论】:

          • 从技术上讲,这仅适用于所有 ctor 都受到保护的情况。
          • 友元类也可以调用受保护的构造函数(不仅仅是派生类)。
          • ...如果一个对象的成员是常量(由构造函数设置)但需要是公共的,但从不由任何其他公共访问设置,保证不会在其他地方创建对象,因此也不会在其他任何地方修改数据。
          【解决方案8】:

          让子类使用实例化器不能直接访问的构造函数。

          【讨论】:

            【解决方案9】:

            一种用途可能是工厂模式

            【讨论】:

            • 如果您能通过添加一些实际示例来详细说明您的答案,那就太好了。
            猜你喜欢
            • 2023-04-05
            • 1970-01-01
            • 1970-01-01
            • 2013-08-04
            • 1970-01-01
            • 1970-01-01
            • 2016-04-07
            • 1970-01-01
            • 2021-10-05
            相关资源
            最近更新 更多