我目前正在开发一个使用C ++的大学项目,其中一项任务是使用继承和多态来建立社交网络。目前我有一个Node类,用于 Map 和 Multimap (两者都是手动创建的,不会从std中使用)。节点可以容纳两个变量(例如 key 和 data ),在我使用它的地方,第一个变量可以是指针或字符串(它们让我们使用 std :: string )。
我遇到的问题是,当我从“root”类继承( Object )并使用“Object”作为“key”的数据类型时,我无法通过使用std作为其构造函数的参数创建的字符串,因为它不从我的Object类继承。一种解决方案是实现我自己的字符串类并使其继承自Object,但我正在寻找其他解决方法。
如果上述逻辑有任何问题,请告诉我,因为我刚刚开始使用C ++。
编辑1(我的节点的一些代码):
class TempNode
{
private:
TempNode* next;
Key key;
T value;
public:
TempNode();
explicit TempNode(const Key thisKey, const T thisValue, TempNode* thisNext = NULL)
: key(thisKey)
, value(thisValue)
, next(thisNext)
{
}
inline Key getKey() { return key; }
inline T getValue() { return value; }
inline TempNode* getNext() { return next; }
inline void setNext(TempNode* thisNext) { next = thisNext; }
};
字符串或人物类型目前仅在键中使用,但这与另一个使用模板的实现(工作正常),但我的老师现在要求我们将继承应用于整个项目(我猜它已经习惯了。
答案 0 :(得分:1)
要使用继承实现此功能,您可以将Key
视为专门设计为地图/多图实现中的键的数据类型。 Key
继承自Object
,但它可以提供自己的,特定于键的函数,例如 - 函数repr()
,它生成地图用于某些地图的表示 - 具体操作(可能作为散列或排序等的基础)。
地图/多图必须以Key
个对象存储为指针(或std::unique_ptr
或std::shared_ptr
或其他任何适当的方式)的方式使用,但不能用作Key
个对象的副本。
所以我们有:
struct Object
{
virtual ~Object()
{ }
};
/* Key class. Pointers of this type are inserted
into the map. */
class Key : public Object
{
public:
/* Must be supported by all keys: */
virtual std::string repr() const = 0;
};
我们还假设Person
个对象有一个单独的定义:
struct Person : Object
{
Person(const std::string &name)
: name_(name)
{ }
std::string name_;
};
根据你的规范,有两种Key
:一种代表字符串,必须用字符串初始化,另一种代表人,必须用人指针初始化(我假设person-keys实际上并不拥有这些指针,因此只要人员密钥存在,你需要确保他们指向的人对象保持活着。
我们通过将Key
专门化为两个派生类PersonKey
和StringKey
来实现这一点:
class PersonKey : public Key
{
public:
PersonKey(Person *person_ptr)
: Key() , person_ptr_(person_ptr)
{ }
virtual std::string repr() const
{
if (person_ptr_ != 0)
return std::string("Person/") + person_ptr_->name_;
else
return "<NUL>";
}
private:
Person *person_ptr_;
};
class StringKey : public Key
{
public:
StringKey(const std::string &str)
: Key() , str_(str)
{ }
virtual std::string repr() const
{
return str_;
}
private:
std::string str_;
};
当您在地图/多地图中插入广告时,会生成Key
个对象(您表示为Key*
或Key&
或std::unique_ptr<Key>
)。如果要插入字符串,可以将它们生成为StringKey
个对象,当您想要将它们作为人物指针插入时,可以使用PersonKey
- 但是您插入的键的数据类型不会反映专业化。
以下是一般Key
对象的示例(实现为std::unique_ptr<Key>
,但如果您不怕内存泄漏,则可以使用Key*
):
int main()
{
/* General key object: */
std::unique_ptr<Key> mykey;
/* Now it points to a string-key, initialized using
a string, as required: */
mykey.reset(new StringKey("hello"));
std::cout << "repr(mykey) == \""
<< mykey->repr()
<< '"'
<< std::endl;
/* Now the same key object is made to refer to
a person object: */
Person person("me");
mykey.reset(new PersonKey(&person));
std::cout << "repr(mykey) == \""
<< mykey->repr()
<< '"'
<< std::endl;
return 0;
}
上述代码的必要标题是:
#include <iostream>
#include <memory>
#include <string>
(但memory
仅在我使用std::unique_ptr
时才需要,这对解决您的问题实际上并不是必需的。)
答案 1 :(得分:0)
我认为你真正想要的是模板。使用“根对象”的解决方案将无法使用标准对象和外部库,但您也无法使用带有基元的容器(例如person id(as int)作为键,Person类作为键)值)。
使用模板,您可以说明在编译时您将使用哪种类型,编译器将帮助您遵守自己的规则。它可以这样声明:
template<class T1, class T2>
class Map{
T1 key;
T2 value;
(...)
}
然后你可以或多或少地使用它:
Map<std::String, int> phoneBook;
编译器会保护你并警告你,如果你试图添加,例如float而不是int,你就是Map。但在开始编码之前,我建议你先阅读一些教程,或者甚至一些关于c ++的书。但如果您现在想要开始使用通用,那么您可以启动她:
答案 2 :(得分:0)
您能够在Object变量中存储字符串的唯一方法是,如果字符串类继承自Object类,那么您将不得不实现自己的String类。
这里真正的缺陷是你正在采用Java / C#方法进行设计,其中一个Object变量可以容纳任何东西。在C ++中,处理此类事情的正确方法是使用模板,假设您的Map / Multimap / Node只需要保存一种特定的数据类型。
如果你的容器需要能够保存任何数据类型,我建议使用类型擦除,虽然这对于初学者来说可能有点复杂。