C++ 11声明工厂是基类的朋友

jlc*_*lin 8 c++ inheritance factory friend c++11

我正在尝试为派生类创建一个工厂.我只希望工厂能够创建派生类的实例,所以我已经创建了基础构造函数protected; 派生类只使用基类构造函数,因此它们的构造函数protected也是如此.

我试图将工厂声明为基类的朋友,以便它可以访问protected构造函数.当我使用此命令编译时

clang++ -std=c++11 -stdlib=libc++ Friends.cpp -o Friends
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

Friends.cpp:23:20: error: calling a protected constructor of class 'A'
        return new T(i);
               ^
Friends.cpp:42:16: note: in instantiation of function template specialization 'Create<A>' requested
      here
        A* a = Create<A>(1);
           ^
Friends.cpp:30:25: note: declared protected here
             using Base::Base;
                    ^
Run Code Online (Sandbox Code Playgroud)

与派生类的类似错误一起B.

我从stackoverflow.com上读到其他问题的感觉,这在C++ 11中是不可能的,但我不确定为什么.有人可以解释为什么这不起作用,或许可以替代?

示例代码

#include <iostream>

using namespace std;

// Forward declaration
template<class T> T* Create(int i);

class Base {
    public:
        template<class T>
        friend T* Create(int);
        virtual void say() = 0;

    protected:
        Base(int i): i(i) { }   // This won't compile
        int i;
};

// Factory for Base class
template<class T>
T* Create(int i){
    return new T(i);
}

class A: public Base {
    public:
        using Base::Base;
        void say() { cout << "I am A and have a value of " << i << endl; }
};

class B: public Base{
    public:
        using Base::Base;
        void say() { cout << "I am B and have a value of " << i << endl; }
};

int main(){
    cout << "I'm creating A." << endl;
    A* a = Create<A>(1);
    a->say();

    cout << "I'm creating B." << endl;
    B* b = Create<B>(2);
    b->say();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Pra*_*ian 5

从基类继承构造函数时,无论将using声明放在派生类中的哪个位置,它都会保留原始构造函数的访问权限.

来自§12.9/ 4 [class.inhctor]

如此声明的构造函数具有与相应构造函数相同的访问权限X....

如果您明确地将构造函数添加到派生类而不是继承它们,则可以修复错误Base.

A(int i) : Base(i) {}
Run Code Online (Sandbox Code Playgroud)

B(int i) : Base(i) {}
Run Code Online (Sandbox Code Playgroud)

现场演示

当然,另一个解决方案是制作Base构造函数public.您也可以创建它的析构函数protected,但由于纯虚拟成员函数无法实现此类,因此无需进行实例化.

class Base {
    public:
        template<class T>
        friend T* Create(int);
        virtual void say() = 0;

        Base(int i): i(i) { }   // This won't compile
        int i;
    protected:
        ~Base() {}
};
Run Code Online (Sandbox Code Playgroud)

现场演示

  • 作为记录,我不知道谁有这个想法,让 `using Base::Base` 的行为与 `using Base::foo` 不同,但这确实令人困惑(再一次)。 (2认同)