派生类中的反射工厂C++无法访问受保护的方法
Reflective Factory in C++ Derived class unable to access protected methods?
受到回答Johannes Schaub的回答的启发,我试图实现一个反射工厂。这个想法是,您可以通过将类的名称传递给一个方法来创建对象,该方法在堆上创建相关对象并返回指向公共基类的指针。如有必要,使用 dynamic_cast 和 RTTI,可以将对象转换回其原始类型。应该能够使用反射工厂,如下所示:
// Base is the base class of all objects to create.
class Factory: public AbstractFactory<Base>
{
public:
Factory()
{
m_map["DerivedA"] = &AbstractFactory::createInstance<DerivedA>;
m_map["DerivedB"] = &AbstractFactory::createInstance<DerivedB>;
}
};
int main()
{
Factory factory;
Base *a = factory.Create("DerivedA");
DerivedA *aa = dynamic_cast<DerivedA*>(a);
// etc..
}
到目前为止,我得到了这个工作。但是,下面的代码有两个主要问题。它很丑陋,如果我使抽象工厂的方法受到保护,它会抱怨它无法访问createInstance()
方法。这是我不明白的。根据定义,派生类应该能够访问基类的受保护方法。我在VS 2008中测试了代码。进一步说明:我知道基类并不是真正抽象的,因为它不包含纯虚函数。我知道std::function,但到目前为止我还没有使用它。也许我将来会这样做。
#include <iostream>
#include <map>
#include <typeinfo>
#include <string>
struct Base
{
virtual std::string SayHello() = 0;
};
struct DerivedA: public Base
{
virtual std::string SayHello()
{
return "Hello from DerivedA";
}
};
struct DerivedB: public Base
{
virtual std::string SayHello()
{
return "Hello form DerivedB";
}
};
/**
* @brief Reflective Factory class. Creates objects of classes which derive from
* a common base class.
*
*/
template<class BASE_T>
struct AbstractFactory
{
// Macro to call ptrs to member functions as recommended in the C++ FAQ lite.
// http://www.parashift.com/c++-faq-lite/pointers-to-members.html
#define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember))
// Recall funcion ptr syntax for members: ReturnType (class::*) (Arguments)
// using a typedef makes it easier..
typedef BASE_T* (AbstractFactory::*func_ptr_type) ();
// retType^ ClassName^ AliasName^ Arguments^
typedef std::map<std::string, func_ptr_type> map_type;
template<typename DERIVED_T>
BASE_T * createInstance()
{ return new DERIVED_T; }
map_type m_map;
/**
* @brief Creates an object from a class with the name given as string.
*/
BASE_T * Create(std::string className)
{
// Note the last () at the end.
return CALL_MEMBER_FN(*this, m_map[className])();
}
#undef CALL_MEMBER_FN
};
class Factory: public AbstractFactory<Base>
{
public:
Factory()
{
m_map["DerivedA"] = &AbstractFactory::createInstance<DerivedA>;
m_map["DerivedB"] = &AbstractFactory::createInstance<DerivedB>;
}
};
int main()
{
Factory factory;
Base *a = factory.Create("DerivedA");
DerivedA *aa = dynamic_cast<DerivedA*>(a);
std::cout << typeid(a).name() << std::endl;
std::cout << typeid(*a).name() << std::endl;
std::cout << typeid(aa).name() << std::endl;
std::cout << aa->SayHello() << std::endl;
std::cin.get();
return 0;
}
更新
我使用 VS 2008 得到的确切错误是(在德语中,对不起不是我的选择......
1>------ Erstellen gestartet: Projekt: ReflectiveFactory, Konfiguration: Debug Win32 ------
1>Kompilieren...
1>main.cpp
1>.main.cpp(82) : error C2248: "AbstractFactory<BASE_T>::createInstance": Kein Zugriff auf protected Member, dessen Deklaration in der AbstractFactory<BASE_T>-Klasse erfolgte.
1> with
1> [
1> BASE_T=Base
1> ]
1> .main.cpp(55): Siehe Deklaration von 'AbstractFactory<BASE_T>::createInstance'
1> with
1> [
1> BASE_T=Base
1> ]
1>.main.cpp(83) : error C2248: "AbstractFactory<BASE_T>::createInstance": Kein Zugriff auf protected Member, dessen Deklaration in der AbstractFactory<BASE_T>-Klasse erfolgte.
1> with
1> [
1> BASE_T=Base
1> ]
1> .main.cpp(55): Siehe Deklaration von 'AbstractFactory<BASE_T>::createInstance'
1> with
1> [
1> BASE_T=Base
1> ]
最终用户必须可以访问 Create
方法,这意味着该方法要么在 AbstractFactory
中public
,要么移动到 Factory
并在那里公开。AbstractFactory
中的其余代码可以受到保护。
似乎只有 gcc 接受代码(clang++,comeau 拒绝它),它可以被理所当然地拒绝(我必须研究标准)。无论如何,一个简单的解决方法是创建一个帮助程序函数,该函数将为你提供成员函数指针:
template <typename B>
template <typename D>
AbstractFactory<B>::func_ptr_type AbstractFactory<B>::getCreateInstancePtr() const {
return &AbstractFactory<B>::createInstance<D>;
}
AbstractFactory
模板的这个模板成员方法可以受到保护,因为你在实际Factory
中直接在自己的基础上调用它:
Factory::Factory() {
m_map["DerivedA"] = getCreateInstancePtr<DerivedA>();
m_map["DerivedB"] = getCreateInstancePtr<DerivedB>();
}
与标准核对后:
11.5p1 [类保护]
除非形成指向成员的指针 (5.3.1),否则访问必须通过 指向派生类本身(或从该类派生的任何类)的指针、引用或对象 (5.2.5)。如果访问要形成指向成员的指针,则嵌套名称说明符应命名派生类(或从该类派生的任何类)。
也就是说,表达式m_map["DerivedA"] = &AbstractFactory::createInstance<DerivedA>;
不正确,而m_map["DerivedA"] = &Factory::createInstance<DerivedA>;
是正确的(关于访问说明符,但不是类型,左侧是B* (AbstractFactory<B>::*)( std::string )
,右侧是B* (Factory::*)( std::string )
,因此分配将失败。
这与其他任何地方的protected
语义配合得很好,特别是无法访问您自己的基本子对象以外的受保护成员:
class base {
protected:
int x;
};
struct derived : base {
static void f( base& b ) {
b.x = 5; // Error: cannot access base::x from this context
}
};
- 继承和友元函数,从基类访问受保护的成员
- C++:为什么无法在派生类中访问受保护的构造函数?
- 如何从其他结构访问受保护的结构变量
- 从模板化父类中的派生内部类访问受保护的成员变量
- 有没有办法通过 main 函数访问受保护的矢量大小而无需将其转换为公共?
- 在派生类的构造函数初始化中无法访问受保护的函数
- 无法通过指针或对象 c++ 访问受保护的成员
- C 继承访问受保护的数据成员
- 访问受保护的成员
- 尝试从基类访问受保护的构造函数时出现错误 C2248
- 如何通过运算符<<的重载访问受保护的功能?C++
- 从公共派生类访问受保护的成员
- Boost单元测试夹具继承测试类,是否可以访问受保护的方法
- 如果我使用强制转换访问受保护的成员,可能会出现什么问题?
- 通过继承访问受保护的成员
- 访问受保护的变量 - 继承和子类的复杂情况
- 为什么我无法从基类的实例访问受保护的成员?
- 访问受保护成员的公共方法
- 通过好友访问受保护的成员
- 从另一个类 C++ 访问受保护的函数