代码之家  ›  专栏  ›  技术社区  ›  darune

如果对象是堆栈创建的(包括继承的类型),是否可能发出编译错误?

  •  8
  • darune  · 技术社区  · 6 年前

    基本上,我希望所有子类型都是通过工厂方法创建的(我有一个高域层次结构,有200多个类)。

    为了 new ,这不是问题,因为可以在 新的 私人)。

    class A{
    protected:
      A();
    public:
      template<class T, typename... ARGUMENTS>
      static T* create(ARGUMENTS&&... arguments);
    };
    
    class B : public A {
    public:
      B();
    };
    
    void test() {
      B b;//compile error wanted here - but as a consequence of inheriting A
    }
    

    这里是一个“库/框架”类。而B是一个“用户创建的类”。在B上需要typedef或类似的类型是可以的。

    更新:我在上添加了“create”函数,我打算使用它来创建对象。

    2 回复  |  直到 6 年前
        1
  •  6
  •   Caleth    6 年前

    在构造 A 只有在尸体里 A::create

    #include <utility>
    
    class A{
    private:
      struct create_token
      { 
        create_token(const create_token &) = delete; 
        create_token& operator=(const create_token &) = delete; 
        create_token(create_token &&) = default; 
        create_token& operator=(create_token &&) = default; 
      };
    protected:
      A(create_token) {}
    public:
      template<class T, typename... ARGUMENTS>
      static T* create(ARGUMENTS&&... arguments)
      {
        // Whatever creation mechanism here
        return new T(create_token{}, std::forward<ARGUMENTS>(arguments)...);
      }
    };
    
    class B : public A {
    public:
      template <typename Token> // Can't name A::create_token, it is private
      B(Token tok) : A(std::move(tok)) {}
      B(){} // Will always lack a `create_token`
    };
    
    int main() {
      B b;//compile error wanted here - but as a consequence of inheriting A
      B* b = A::create<B>();
    }
    

    See it live

        2
  •  1
  •   florestan    6 年前

    这是另一种依赖于检查派生类构造函数是否是私有的方法。但说实话,我更喜欢@caleth给出的解决方案

    #include <type_traits>
    #include <iostream>
    #include <type_traits>
    
    
    template<typename T, typename... Args>
    struct constructor_tag{};
    
    
    
    class A{
    protected:
    
    
        template<typename T, typename... Args>
        A(constructor_tag<T, Args...>) {
            static_assert(!std::is_constructible_v<T, Args...>, "CONSTRUCTOR MUST NOT BE PUBLIC");
        };
    
    
    public:
        template<class T, typename... ARGUMENTS>
        static T* create(ARGUMENTS&&... arguments) {
            return new T(std::forward<ARGUMENTS>(arguments)...);
        }
    };
    
    class B : public A {
    
        friend class A;
        B() : A(constructor_tag<B>{}) {}
    public:
    };
    
    class C : public A {
        friend class A;
    
        C () : A(constructor_tag<C>{}) {}
    
        C(int) : A(constructor_tag<C, int>{}) {}
    public:
    
    };
    
    
    // Following class will not compile because the constructor is public
    
    //class D : public A {
    //    friend class A;
    //
    //public:
    //    D () : A(constructor_tag<D>{}) {}
    //
    //};
    
    void test() {
    
        // B b; //calling a private constructor of class 'B'
        // C c(5);//calling a private constructor of class 'A'
    
        A::create<B>();
        A::create<C>(5);
        A::create<C>();
    }
    
    int main() {
    
    
        test();
    }