返回指向子类的指针的好方法
Good methods to return pointers pointing to subclass
这是我必须面对的一个设计挑战。基类的子类有它自己的特定函数,这些函数没有在基类中定义。我需要设计一个方法,这样我就可以根据输入日期生成不同的子类实例。
作为函数CCD_ 2的传入参数的输入数据CCD_。预先存在的设计(即下面列出的FactoryMethod)的问题是,客户端必须向下转换指向基的返回指针,才能调用仅在子类中定义的函数。在当前的设计中,这个方法是有问题的b/c,我们不知道在FactoryMethod中创建了什么子类。我只能考虑两种潜在的解决方案
解决方案1>在基中引入一个类型,该类型存储指向基的指针的类型信息。有没有一个好的例子向我展示了最佳实践?
解决方案2>在FactoryMethod的实现中返回指向子类而不是基的指针。再说一遍,有没有一个好的例子来展示这一点?
class Base {
public:
...
virtual void BaseFuncA() {}
};
class SubClassA : public Base {
public:
...
void SubClass_A_Func2() {}
}
class SubClassB : public Base {
public:
...
void SubClass_B_Func3() {}
}
Base* FactoryMethod(Data)
{
if (Data designed for SubClassA)
return new SubClassA
if (Data designed for SubClassB)
return new SubClassB
...
}
问题:SubClassA
的客户端必须向下转换才能调用子类函数
SubClassA* ptr = dynamic_cast<SubClassA*> (pointer to Base*);
众所周知,如果你总是要处理代码中的下转换,那么设计就有缺陷。
问题>有没有一本好书/资源可以让我找到这个问题的实用解决方案。换句话说,代码的客户端不必为了使用子类中定义的函数而向下转换指针。例如,工厂方法可以通过采用boost::variant来返回子类指针?
BTW:将所有功能放入Base并在Base中提供虚拟实现是不现实的。即使您可以这样做,您也无法在没有下转换的情况下获得子类提供的真正功能。
尝试阅读有关访问者模式的信息,以避免降级。希望能有所帮助。
http://en.wikipedia.org/wiki/Visitor_pattern
处理这一问题的一种方法是使用消息传递系统,下面是游戏引擎如何通过消息传递而不是向调用函数投射指针来处理执行任务和请求数据的代码示例。
#include <iostream>
#include <stdio.h>
#include <list>
#include <map>
using namespace std;
struct Vector3
{
public:
Vector3() : x(0.0f), y(0.0f), z(0.0f)
{}
float x, y, z;
};
enum eMessageType
{
SetPosition,
GetPosition,
};
class BaseMessage
{
protected: // Abstract class, constructor is protected
BaseMessage(int destinationObjectID, eMessageType messageTypeID)
: m_destObjectID(destinationObjectID)
, m_messageTypeID(messageTypeID)
{}
public: // Normally this isn't public, just doing it to keep code small
int m_destObjectID;
eMessageType m_messageTypeID;
};
class PositionMessage : public BaseMessage
{
protected: // Abstract class, constructor is protected
PositionMessage(int destinationObjectID, eMessageType messageTypeID,
float X = 0.0f, float Y = 0.0f, float Z = 0.0f)
: BaseMessage(destinationObjectID, messageTypeID)
, x(X)
, y(Y)
, z(Z)
{
}
public:
float x, y, z;
};
class MsgSetPosition : public PositionMessage
{
public:
MsgSetPosition(int destinationObjectID, float X, float Y, float Z)
: PositionMessage(destinationObjectID, SetPosition, X, Y, Z)
{}
};
class MsgGetPosition : public PositionMessage
{
public:
MsgGetPosition(int destinationObjectID)
: PositionMessage(destinationObjectID, GetPosition)
{}
};
class BaseComponent
{
public:
virtual bool SendMessage(BaseMessage* msg) { return false; }
};
class RenderComponent : public BaseComponent
{
public:
/*override*/ bool SendMessage(BaseMessage* msg)
{
// Object has a switch for any messages it cares about
switch(msg->m_messageTypeID)
{
case SetPosition:
{
// Update render mesh position/translation
cout << "RenderComponent handling SetPositionn";
}
break;
default:
return BaseComponent::SendMessage(msg);
}
return true;
}
};
class Object
{
public:
Object(int uniqueID)
: m_UniqueID(uniqueID)
{
}
int GetObjectID() const { return m_UniqueID; }
void AddComponent(BaseComponent* comp)
{
m_Components.push_back(comp);
}
bool SendMessage(BaseMessage* msg)
{
bool messageHandled = false;
// Object has a switch for any messages it cares about
switch(msg->m_messageTypeID)
{
case SetPosition:
{
MsgSetPosition* msgSetPos = static_cast<MsgSetPosition*>(msg);
m_Position.x = msgSetPos->x;
m_Position.y = msgSetPos->y;
m_Position.z = msgSetPos->z;
messageHandled = true;
cout << "Object handled SetPositionn";
}
break;
case GetPosition:
{
MsgGetPosition* msgSetPos = static_cast<MsgGetPosition*>(msg);
msgSetPos->x = m_Position.x;
msgSetPos->y = m_Position.y;
msgSetPos->z = m_Position.z;
messageHandled = true;
cout << "Object handling GetPositionn";
}
break;
default:
return PassMessageToComponents(msg);
}
// If the object didn't handle the message but the component
// did, we return true to signify it was handled by something.
messageHandled |= PassMessageToComponents(msg);
return messageHandled;
}
private: // Methods
bool PassMessageToComponents(BaseMessage* msg)
{
bool messageHandled = false;
std::list<BaseComponent*>::iterator compIt = m_Components.begin();
for ( compIt; compIt != m_Components.end(); ++compIt )
{
messageHandled |= (*compIt)->SendMessage(msg);
}
return messageHandled;
}
private: // Members
int m_UniqueID;
std::list<BaseComponent*> m_Components;
Vector3 m_Position;
};
class SceneManager
{
public:
// Returns true if the object or any components handled the message
bool SendMessage(BaseMessage* msg)
{
// We look for the object in the scene by its ID
std::map<int, Object*>::iterator objIt = m_Objects.find(msg->m_destObjectID);
if ( objIt != m_Objects.end() )
{
// Object was found, so send it the message
return objIt->second->SendMessage(msg);
}
// Object with the specified ID wasn't found
return false;
}
Object* CreateObject()
{
Object* newObj = new Object(nextObjectID++);
m_Objects[newObj->GetObjectID()] = newObj;
return newObj;
}
private:
std::map<int, Object*> m_Objects;
static int nextObjectID;
};
// Initialize our static unique objectID generator
int SceneManager::nextObjectID = 0;
int main()
{
// Create a scene manager
SceneManager sceneMgr;
// Have scene manager create an object for us, which
// automatically puts the object into the scene as well
Object* myObj = sceneMgr.CreateObject();
// Create a render component
RenderComponent* renderComp = new RenderComponent();
// Attach render component to the object we made
myObj->AddComponent(renderComp);
// Set 'myObj' position to (1, 2, 3)
MsgSetPosition msgSetPos(myObj->GetObjectID(), 1.0f, 2.0f, 3.0f);
sceneMgr.SendMessage(&msgSetPos);
cout << "Position set to (1, 2, 3) on object with ID: " << myObj->GetObjectID() << 'n';
cout << "Retreiving position from object with ID: " << myObj->GetObjectID() << 'n';
// Get 'myObj' position to verify it was set properly
MsgGetPosition msgGetPos(myObj->GetObjectID());
sceneMgr.SendMessage(&msgGetPos);
cout << "X: " << msgGetPos.x << 'n';
cout << "Y: " << msgGetPos.y << 'n';
cout << "Z: " << msgGetPos.z << 'n';
}
在这种情况下不要使用工厂方法。你必须改变你的设计。看起来您需要其他接口而不是基类,或者根本不需要它。请更详细地描述你的问题,这样我们就可以为你的问题做出适当的设计。
- 在C#中处理C++指针而不使用unsafe的最佳方法
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 对于C++中使用智能指针的指针算术限制,有没有一种变通方法
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 在c++中为我自己的基于指针的数组分配内存的正确方法
- 将成员函数指针作为参数传递给模板方法
- 通过函数指针定义类范围之外的方法
- 模板方法访问正向声明的类仅在没有此指针的情况下无法编译
- 如何访问由共享指针保存的类方法?
- 初始化指向类实例的智能指针并访问其方法
- 我无法使用C++指针指向类方法返回的 std::vector
- 如何在工厂方法中返回指向基于基础操作系统的派生类的有效指针
- 有没有将变量名称转换为双指针的简短方法?
- 在自定义 std::vector-like 容器中处理指针和非指针模板类型的最佳方法是什么?
- 如何在成为指向基类的指针后保留对子类方法的使用?
- 从纯虚拟类 (A) 派生的指针无法访问来自纯类 (B) 的重载方法
- 类指针方法崩溃程序
- 证明两指针方法有效(对和)
- Qt 删除指针方法
- 我如何将一些类的指针方法转换为指针函数