C++中指针的自动返回类型
Automatic Return Type for Pointers in C++
我希望标题不要太混乱。我所拥有的是一个类StorageManager
,它包含从Storage
派生的类的对象列表。下面是一个例子。
struct Storage {}; // abstract
class StorageManager
{
private:
map<string, unique_ptr<Storage>> List; // store all types of storage
public:
template <typename T>
void Add(string Name) // add new storage with name
{
List.insert(make_pair(Name, unique_ptr<Storage>(new T())));
}
Storage* Get(string Name) // get storage by name
{
return List[Name].get();
}
};
假设Position
是一种特殊的存储类型。
struct Position : public Storage
{
int X;
int Y;
};
由于我最后一个问题的答案很好,Add
函数已经工作了。我想改进的是Get
函数。它合理地返回一个指针Storage*
,我可以像下面这样使用它。
int main()
{
StorageManager Manager;
Manager.Add<Position>("pos"); // add a new storage of type position
auto Strge = Manager.Get("pos"); // get pointer to base class storage
auto Pstn = (Position*)Strge; // convert pointer to derived class position
Pstn->X = 5;
Pstn->Y = 42;
}
有没有一种方法可以通过自动返回指向派生类的指针来消除这种指针强制转换?也许使用模板?
使用:
template< class T >
T* Get(std::string const& name)
{
auto i = List.find(name);
return i == List.end() ? nullptr : static_cast<T*>(i->second.get());
}
然后在你的代码中:
Position* p = Manager.Get<Position>("pos");
除了@BigBoss已经指出的之外,我看不出你能为Get
成员函数做些什么,但你可以改进Add
成员以返回使用过的存储。
template <typename T>
T* Add(string Name) // add new storage with name
{
T* t = new T();
List.insert(make_pair(Name, unique_ptr<Storage>(t)));
return t;
}
// create the pointer directly in a unique_ptr
template <typename T>
T* Add(string Name) // add new storage with name
{
std::unique_ptr<T> x{new T{}};
T* t = x.get();
List.insert(make_pair(Name, std::move(x)));
return t;
}
EDIT临时阻止我们使用dynamic_cast
。EDIT2执行MatthieuM的建议。
您还可以通过接受要插入的类型,带有默认参数,但可能会引发附加副本。
当你有一个指向某个类的对象的指针或引用时,你只知道它引用的实际运行时对象要么是该类,要么是某个派生类。auto
在编译时无法知道对象的运行时类型,因为包含auto
变量的代码段可能在一个运行两次的函数中——一次处理一个运行时类型的对象,另一次处理不同运行时间类型的对象!类型系统不能告诉你在一种具有多态性的语言中,确切的类型是什么——它只能提供一些约束。
如果您知道对象的运行时类型是某个特定的派生类(如您的示例中所示),则可以(也必须)使用强制转换。(人们认为最好使用static_cast<Position*>
形式的强制转换,因为强制转换是危险的,这样可以更容易地在代码中搜索强制转换。)
但总的来说,经常这样做是糟糕设计的标志。声明基类并从中派生其他类类型的目的是使的对象能够以相同的方式处理这些类型中的所有,而不必强制转换为特定类型。
- 如果您希望在编译时始终拥有正确的派生类型,而不使用强制转换,那么您别无选择,只能使用该类型的单独集合。在这种情况下,从
Storage
导出Position
可能没有意义 - 如果您可以重新排列事物,使
StorageManager::Get()
的调用者需要用Position
做的一切都可以通过调用不指定Position
特定信息(如坐标)的函数来完成,那么您可以在Storage
中将这些函数变成虚拟函数,并在Position
中实现Position
特定版本的函数。例如,您可以创建一个函数Storage::Dump()
,将其对象写入stdout
。Position::Dump()
将输出X
和Y
,而用于其他可想到的派生类的Dump()
的实现将输出不同的信息 - 有时,您需要能够处理一个对象,该对象可能是几个本质上不相关的类型之一。我怀疑这里可能就是这样。在这种情况下,
boost::variant<>
是一个很好的方法。这个库提供了一个强大的机制,称为Visitor模式,它允许您指定应该对variant
对象可能是的每种类型采取什么操作
除了这个想法看起来很糟糕之外。。。让我们看看我们能做些什么来改善这种情况。
=>要求默认构造是个坏主意
template <typename T>
T& add(std::string const& name, std::unique_ptr<T> element) {
T& t = *element;
auto result = map.insert(std::make_pair(name, std::move(element)));
if (result.second == false) {
// FIXME: somehow add the name here, for easier diagnosis
throw std::runtime_error("Duplicate element");
}
return t;
}
=>盲目降低是个坏主意
template <typename T>
T* get(std::string const& name) const {
auto it = map.find(name);
return it != map.end() ? dynamic_cast<T*>(it->second.get()) : nullptr;
}
但坦率地说,这个体系漏洞百出。而且可能一开始就没有必要。我鼓励你复习一下一般问题,想出一个更好的设计。
- 接收和返回函数指针的函数指针的类型?
- 具有"templated"返回类型和参数的函数指针
- 为什么要为指针返回类型返回一系列字符?
- 返回不同返回类型的函数的函数指针的函数
- 从弱指针返回类型返回共享指针
- 我的问题是关于类成员函数作为类指针的返回类型
- C :无指针的协变返回类型
- 是否可以将“自动”关键字用作函数指针声明中使用初始化的返回类型
- C 返回类型指针声明
- 将结构指针声明为函数的返回类型
- 返回函数指针错误而不带类型定义
- 这个函数指针的尾部返回类型为"this"合法吗
- 在参数包中获取函数指针的返回类型,并将其保存为与其他参数连接的元组
- 功能指针参数的自动返回类型
- 如何将函数指针声明指向模板函数,其返回类型取决于模板类
- 是否可以声明指向未知(编译时)返回类型的函数的指针
- API返回类型--强制将智能指针指向用户
- 重写虚函数协变返回类型(两个指针)
- 将函数指针插入到具有多态返回类型的映射中
- 指针从C 中的函数返回类型