1

我目前正在使用 C++ 进行一个大学项目,我的一项任务是使用继承和多态创建一个社交网络。目前我有一个用于MapMultimap的 Node 类(两者都是手动创建的,而不是从 std 中使用的)。该节点可以保存两个变量(例如keydata),在我使用它的地方,第一个变量可以是指针或字符串(它们让我们使用std::string)。

我遇到的问题是,当我从“根”类(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; }
};

string 或 Person 类型目前仅在key中使用,但这是使用模板的另一个实现(效果很好),但我的老师现在要求我们将继承应用于整个项目(我猜要习惯它)。

4

3 回答 3

1

要使用继承来实现这一点,您可以将其Key视为一种数据类型,专门设计为映射/多映射实现中的键。Key继承自Object,但它可能提供自己的特定于键的函数,例如 - 例如 -repr()生成地图用于某些特定于地图的操作的表示的函数(可能作为散列或排序或其他的基础) .

map/multimap 必须以这样一种方式使用,即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:一种表示字符串并且必须使用字符串进行初始化,另一种表示人员并且必须由人员指针初始化(我假设人员键实际上并不拥有这些指针,因此您需要确保它们指向的人员对象只要人员密钥存在就保持活动状态)。

我们通过专门针对Key两个派生类 aPersonKey和 a来实现这一点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*orKey&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实际上并不是解决您的问题所必需的。)

于 2013-06-26T02:19:30.037 回答
0

您能够在 Object 变量中存储字符串的唯一方法是,如果字符串类继承自您的 Object 类,那么不幸的是,您将不得不实现自己的 String 类。

这里真正的缺陷是您采用 Java/C# 方法进行设计,其中 Object 变量可以保存任何内容。在 C++ 中,处理此类事情的正确方法是使用模板,假设您的 Map/Multimap/Node 只需要保存一种特定的数据类型。

如果您的容器需要能够保存任意数据类型,我建议使用类型擦除,尽管这对于初学者来说可能有点复杂。

于 2013-06-26T00:37:10.827 回答
0

我认为您真正需要的是模板。正如您在标准对象和外部库中看到的那样,您使用“根对象”的解决方案将无法使用,而且您将无法将容器与原语一起使用(例如,个人 id(as int) 作为键,将 Person 类作为价值)。

使用模板,您可以在编译时说出要使用的类型,编译器将帮助您遵守自己的规则。可以这样声明:

template<class T1, class T2>
class Map{
  T1 key;
  T2 value;
  (...)
}

然后你可以或多或少地像这样使用它:

Map<std::String, int> phoneBook;

如果您尝试向 Map 添加例如 float 而不是 int,编译器会保护您并发出警告。但是在你开始编码之前,我建议你先阅读一些教程,或者甚至是一些关于 c++ 的书。但是如果你现在想从通用开始,你可以开始她:

http://www.cplusplus.com/doc/tutorial/templates/

于 2013-06-26T00:32:10.960 回答