保持对C ++中任何对象类型的引用?

时间:2009-10-27 18:35:05

标签: c++ pointers object linked-list

我正在尝试自学C ++,而我一直使用的传统“新语言”练习之一是实现一些数据结构,如二叉树或链表。在Java中,这相对简单:我可以定义一些维护实例变量Object data的类Node,以便有人可以在列表或树的每个节点中存储任何类型的对象。 (后来我使用泛型来修改它;这不是这个问题的内容。)

我找不到类似的,惯用的C ++方式来存储“任何类型的对象”。在C中,我使用void指针;显然,同样的事情适用于C ++,但是当我构造std::string的实例并尝试将其存储到列表/树中时,我会遇到问题(关于从std::string&到{的无效转换的问题{1}})。有这样的方式吗? C ++是否与Java的Object(或Objective-C的NSObject)等效?

奖金问题:如果没有,我需要继续使用无效指针,那么将void*存储到std::string的“正确”方法是什么?我偶然发现了void*,但这似乎对我正在做的事情有点冗长。还有更好的方法吗?

6 个答案:

答案 0 :(得分:12)

与Java不同,C ++没有所有对象继承的基础对象。您想要做的通常做法是使用templates。标准C ++库中的所有容器都使用此方法。

与Java不同,C ++不依赖于多态/继承来实现通用容器。在Java中,所有对象都从Object继承,因此任何类都可以插入到带有Object的容器中。但是,C ++模板是编译时构造,它指示编译器为您使用的每种类型实际生成不同的类。所以,例如,如果你有:

template <typename T>
class MyContainer { ... };

然后,您可以创建一个MyContainer来获取std::string个对象,另一个MyContainer创建int个。

MyContainer<std::string> stringContainer;
stringContainer.insert("Blah");

MyContainer<int> intContainer;
intContainer.insert(3342);

答案 1 :(得分:9)

你可以看一下boost :: any class。它是类型安全的,你可以把它放到标准集合中,你不需要链接任何库,该类在头文件中实现。

它允许您编写如下代码:

#include <list>
#include <boost/any.hpp>

typedef std::list<boost::any> collection_type;

void foo()
{
    collection_type coll;
    coll.push_back(boost::any(10));
    coll.push_back(boost::any("test"));
    coll.push_back(boost::any(1.1));
}

完整文档在此处:http://www.boost.org/doc/libs/1_40_0/doc/html/any.html

答案 2 :(得分:3)

您要找的是模板。它们允许您创建类和函数,允许您采用任何数据类型。

答案 3 :(得分:2)

模板是执行此操作的静态方法。它们的行为类似于Java和C#泛型,但它们是100%静态的(编译时)。如果你需要在同一个容器中存储不同类型的objetcs,请使用它(其他答案很好地描述了这一点)。

但是,如果您需要在同一容器中存储不同类型的对象,则可以通过将指针存储在基类上以动态方式执行此操作。当然,您必须定义自己的对象层次结构,因为C ++中没有这样的“Object”类:

#include <list>

class Animal {
public:
   virtual ~Animal() {}
};

class Dog : public Animal {
public:
   virtual ~Dog() {}
};

class Cat : public Animal {
public:
   virtual ~Cat() {}
};

int main() {
    std::list<Animal*> l;
    l.push_back(new Dog);
    l.push_back(new Cat);

    for (std::list<Animal*>::iterator i = l.begin(); i!= l.end(); ++i)
        delete *i;

    l.clear();

    return 0;
}

智能指针更易于使用。 boost::smart_ptr的示例:

std::list< boost::smart_ptr<Animal> > List;
List.push_back(boost::smart_ptr<Animal>(new Dog));
List.push_back(boost::smart_ptr<Animal>(new Cat));
List.clear(); // automatically call delete on each stored pointer

答案 4 :(得分:1)

您应该能够使用标准的C风格演员阵容将void*投射到string*。请记住,引用在使用时不会被视为指针,它被视为普通对象。因此,如果您通过引用函数传递值,则仍需要取消它以获取其地址。

然而,正如其他人所说,更好的方法是使用模板

答案 5 :(得分:1)

static_cast<char*>(str.c_str())

对我来说很奇怪。 str.c_str()检索类似C的字符串,但类型为const char *,要转换为char *,您通常会使用const_cast<char *>(str.c_str())。除非这样做不好,因为你要干预string的内部。你确定你没有收到警告吗?

您应该可以使用static_cast<void *>(&str)。您收到的错误消息告诉我您有其他错误,所以如果您可以发布代码,我们可以查看它。 (数据类型std::string&是对string的引用,而不是指向一个的引用,因此错误消息是正确的。我不知道你是如何获得引用而不是指针的。 )

而且,是的,这很冗长。它的目的是。在C ++程序中,Casting通常被认为是一种难闻的气味,Stroustrup希望演员阵容很容易找到。正如在其他答案中所讨论的,构建任意基类型数据结构的正确方法是使用模板,而不是强制转换和指针。