如何允许一个类由另一个类创建而不使用'friend'但允许继承?
How to allow a class to be created by another without using 'friend' but allow inheritence?
我的游戏引擎总共有三个类,一个抽象的IComponent类,其中所有组件都继承自它,一个组件类(在本例中我将使用RenderComponent(和一个ComponentManager。我希望 ComponentManager 类能够使用 RenderComponent 的构造函数,但我不希望任何其他类创建 RenderComponent 的实例,但我不想使用"friend",因为我希望客户用户组件从 IComponent 继承并自动在 ComponentManager 中使用,而不允许实例化它们自己的组件。代码示例模糊地显示了我想要发生的行为:
class GameObject;
class IComponent
{
private:
IComponent() { }
~IComponent() { }
public:
GameObject* Parent;
}
class RenderComponent : IComponent
{
public:
RenderComponent() { }
~RenderComponent() { }
}
class ComponentManager
{
public:
ComponentManager() { }
~ComponentManager() { }
// normally this would be a template function, but for the sake of this example I will directly use RenderComponent
RenderComponent* CreateComponent()
{
// this would not throw a compiler error
return new RenderComponent();
}
}
int main()
{
ComponentManager manager;
// even though the constructor of RenderComponent is public, this would throw an error
RenderComponent* render = new RenderComponent();
// this however would work perfectly fine
RenderComponent* render = manager.CreateComponent();
}
重申一下,我希望它使创建组件的用户工作量最小。当然,另一种选择是同时拥有两个公共的构造函数,但拥有它,这样尽管您可以在任何您想要的地方创建组件,但它将毫无用处。
如果使用工厂设计模式,ComponentManager
不需要了解IComponent
的具体子类型。没有必要将其声明为子类型的朋友。它可以简单地使用工厂来构造对象。
IComponent
子类型的创建者需要注册一种方法来构造子类型的实例。它们向可以构造类实例的工厂注册函数或类。
示例程序
#include <iostream>
#include <map>
#include <string>
class GameObject;
class IComponent
{
// Make sure that sub-classes of IComponent can use the constructor
// and the destructor.
protected:
IComponent() { }
~IComponent() { }
public:
GameObject* Parent;
};
// Define a function type that can construct a Component.
using ComponentConstructor = IComponent* (*)();
// Define the interface for the factory.
class ComponentFactory
{
public:
// A type alias for simpler coding.
using ConstructorMap = std::map<std::string, ComponentConstructor>;
// Allow creators of sub-classes of IComponent to register a
// function that can be used to construct the sub-type.
static void registerComponentConstructor(std::string const& componentType,
ComponentConstructor constructor);
// Construct a Component by providing a name corresponding
// to the derived sub-type of IComponent.
static IComponent* constructComponent(std::string const& componentType);
private:
// Private function that maintains a map of
// constructors.
static ConstructorMap& getConstructrMap();
};
// -----------------------------------------------------
// BEGIN implementation of ComponentFactory.
// It can, obviously, be in a .cpp file of its own.
void ComponentFactory::registerComponentConstructor(std::string const& componentType,
ComponentConstructor constructor)
{
getConstructrMap()[componentType] = constructor;
}
IComponent* ComponentFactory::constructComponent(std::string const& componentType)
{
ConstructorMap& constructorMap = getConstructrMap();
ConstructorMap::iterator iter = constructorMap.find(componentType);
if ( iter != constructorMap.end() )
{
return iter->second();
}
else
{
return nullptr;
}
}
ComponentFactory::ConstructorMap& ComponentFactory::getConstructrMap()
{
static ConstructorMap theMap;
return theMap;
}
// END implementation of ComponentFactory.
// -----------------------------------------------------
// ComponentManager can use ComponentFactory to
// construct Components.
class ComponentManager
{
public:
ComponentManager() { }
~ComponentManager() { }
IComponent* CreateComponent(std::string const& componentType)
{
return ComponentFactory::constructComponent(componentType);
}
};
// Test code.
// Construct IComponents by using appropriate names.
int main()
{
ComponentManager m;
IComponent* ic1 = m.CreateComponent("RenderComponent");
if ( ic1 == nullptr )
{
std::cout << "Unable to construct a Component of type RenderComponent.n";
}
else
{
std::cout << "Successfully constructed a Component of type RenderComponent.n";
}
IComponent* ic2 = m.CreateComponent("AnotherTypeOfComponent");
if ( ic2 == nullptr )
{
std::cout << "Unable to construct a Component of type AnotherTypeOfComponent.n";
}
else
{
std::cout << "Successfully constructed a Component of type AnotherTypeOfComponent.n";
}
IComponent* ic3 = m.CreateComponent("FooComponent");
if ( ic3 == nullptr )
{
std::cout << "Unable to construct a Component of type FooComponent.n";
}
else
{
std::cout << "Successfully constructed a Component of type FooComponent.n";
}
}
// Client components.
// Without these, no Component can be constructed.
namespace Module1
{
class RenderComponent : IComponent
{
public:
RenderComponent() { }
~RenderComponent() { }
static IComponent* constructComponent()
{
return new RenderComponent();
}
struct Initer
{
Initer()
{
ComponentFactory::registerComponentConstructor("RenderComponent",
RenderComponent::constructComponent);
}
};
};
// The constructor makes sure that
// RenderComponent::constructComponent() is
// registered as the function to be called to
// construct objects of type RenderComponent when
// the name "RenderComponent" is used.
//
// A different method may be used for the purpose but
// this seems like a straight forward method to do that.
static RenderComponent::Initer initer;
}
namespace Module2
{
class AnotherTypeOfComponent : IComponent
{
public:
AnotherTypeOfComponent() { }
~AnotherTypeOfComponent() { }
static IComponent* constructComponent()
{
return new AnotherTypeOfComponent();
}
struct Initer
{
Initer()
{
ComponentFactory::registerComponentConstructor("AnotherTypeOfComponent",
AnotherTypeOfComponent::constructComponent);
}
};
};
// The constructor makes sure that
// AnotherTypeOfComponent::constructComponent() is
// registered as the function to be called to
// construct objects of type AnotherTypeOfComponent when
// the name "AnotherTypeOfComponent" is used.
static AnotherTypeOfComponent::Initer initer;
}
输出
Successfully constructed a Component of type RenderComponent.
Successfully constructed a Component of type AnotherTypeOfComponent.
Unable to construct a Component of type FooComponent.
首先,我要感谢 R Sahu 提供他的答案,但在他的示例中,仍然允许用户做我首先想要避免的事情,随机能够创建一个组件的实例:
IComponent* component = new RenderComponent();
现在我意识到我想要的是不可能的,没有办法限制构造函数/析构函数对用户的访问,而不会限制对组件管理器的访问。因此,要么我的实现是错误的或不完整的(这不太可能,但有可能(,要么我要求的东西不合逻辑(最有可能的答案(。
因此,我只是选择将所有内容公开,只是使随机创建的组件无用,在我的引擎文档中,我将描述您必须使用GameObject::AddComponent((才能创建和使用组件。
谢谢。
- 继承函数的重载解析
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 混合组合和继承的C++问题
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 从类继承时,继承的类是否会通过父类重新定义继承的变量
- 公共与私人继承
- 如何创建从同一类继承的不同对象的向量
- 如何从另一个文件继承私有成员变量和公共函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 带有继承的C++工厂
- 我应该避免多重实现继承吗
- C++继承更改成员
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 关于C++中具有多重继承"this"指针的说明
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 如何允许一个类由另一个类创建而不使用'friend'但允许继承?