gpt4 book ai didi

c++ - C++派生类中的反射工厂无法访问 protected 方法?

转载 作者:行者123 更新时间:2023-11-30 02:04:47 27 4
gpt4 key购买 nike

answer Johannes Schaub's answer 的启发,我尝试实现一个反射工厂。这个想法是,您可以通过将类的名称传递给在堆上创建相关对象并返回指向公共(public)基类的指针的方法来创建对象。如果需要,可以使用 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() 方法。这是我不明白的事情。根据定义,派生类应该能够访问基类的 protected 方法。我在 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方法必须可供最终用户访问,这意味着该方法是 publicAbstractFactory或者移至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 [class.protected]

Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5). If the access is to form a pointer to member, the nested-name-specifier shall name the derived class (or any class derived from that class).

也就是表达式m_map["DerivedA"] = &AbstractFactory::createInstance<DerivedA>;不正确,而 m_map["DerivedA"] = &Factory::createInstance<DerivedA>;是正确的(关于访问说明符,但不是类型,左侧是 B* (AbstractFactory<B>::*)( std::string ),右侧是 B* (Factory::*)( std::string ),因此分配将失败。

这与 protected 的语义相得益彰在其他任何地方,尤其是在无法访问除您自己的基本子对象之外的 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++ - C++派生类中的反射工厂无法访问 protected 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10193280/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com