1

I'm currently working on a college project with C++ and one of my assignments is to make a social network using inheritance and polymorphism. Currently I have a Node class that is used on a Map and Multimap (both are created manually and not used from the std). The node can hold two variables (key and data for example) and where I'm using it, the first variable can either be a pointer or a string (they let us use std::string).

The problem I'm having is that when I inherit from the "root" class (Object) and use "Object" as a data type for "key", I'm unable to pass a string created with the std as parameter to its constructor, because it doesn't inherit from my Object class. One solution is to implement my own string class and make it inherit from Object, but I was searching for other workarounds.

If there's any problem with the logic above, please tell me as I'm just beginning with C++.

EDIT 1 (some code for my Node):

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; }
};

The string or Person types are currently used only in key, but that is with another implementation using templates (which works fine), but my teacher now requires us to apply inheritance to the entire project (to get used to it I guess).

7
  • 2
    Please use some example code to show what you're currently trying, even if you know it's wrong. Commented Jun 26, 2013 at 0:28
  • You could wrap std::string in some class derived from Object, therefore it's possible. Commented Jun 26, 2013 at 0:43
  • @aschepler I added my Node class and some more explanation. Commented Jun 26, 2013 at 0:48
  • So Key and T are fixed types? Or is the template declaration missing? Commented Jun 26, 2013 at 0:48
  • @DyP it's missing because I'm currently editing it and forgot to add it, but yes, that code is used in a template, what I was trying to do is add Object as the type for key, but the problem arises when I want to use a string from the std as key for the Node. Commented Jun 26, 2013 at 0:51

3 Answers 3

1

To implement this using inheritance, you think of Key as a data type specifically designed as a key in your map/multimap implementation. Key inherits from Object, but it may provide its own, key-specific functions, such as – for example – a function repr() which generates a representation used by the map for some map-specific operations (maybe as a basis for hashing, or sorting or whatever).

The map/multimap must be used in such a way that the Key objects are stored as pointers (or std::unique_ptr, or std::shared_ptr, or whatever is appropriate), but not as copies of Key objects.

So we have:

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;
};

We also assume there is a separate definition of Person objects:

struct Person : Object
{
  Person(const std::string &name)
    : name_(name)
  { }

  std::string name_;
};

According to your specification, there are two flavours of Key: One that represents strings and must be initialized using a string, and another one that represents persons and must be initialized by a person pointer (I'll assume that the person-keys do not actually own these pointers, so you need to make sure the person objects they point to stay alive as long as the person-key exists).

We implement this by specializing Key into two derived classes, a PersonKey and 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_;
};

When you make insertions into your map/multimap, you generate Key objects (which you represent as Key* or Key& or std::unique_ptr<Key>). When you want to insert a string, you generate them as StringKey objects, and when you want to insert them as person-pointers, you use PersonKey – but the data type of the key you insert will not reflect the specialization.

Here is an example of a general Key object (implemented as std::unique_ptr<Key>, but you may just use Key* if you are not afraid of memory leaks):

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;
}

Necessary headers for the code above are:

#include <iostream>
#include <memory>
#include <string>

(But memory is only required for my use of std::unique_ptr, which is not actually necessary to solve your problem.)

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! This seems like a better way to implement it.
0

I think what you are really looking for are templates. Your solution with "root object" won't work as you can see with standard objects and external libraries but also you will not be able to use your containers with primitives (for example person id(as int) as key, and Person class as value).

With templates you can say what type you are going to work with at compile time and compiler will help you to obey your own rules. It can be declared like this:

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

Then you can use it more or less like this:

Map<std::String, int> phoneBook;

And compiler will guard you and warn, if you try to add, for example float instead of int, to you Map. But before you start coding I advice you to read some tutorials first, or maybe even some book on c++ in general. But if you want to start with generic right now, you can start her:

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

1 Comment

Oh, I already implemented the entire project using templates for Map, Multimap, Node and Graph, but the assignment now is to use inheritance.
0

The only way you'd be able to store a string in your Object variable was if the string class inherited from your Object class, so you will have to implement your own String class unfortunately.

The real flaw here is that you are taking a Java/C# approach to design, where an Object variable can hold anything. In C++ the proper way to handle such things is through the use of templates, supposing your Map/Multimap/Node only need to hold one specific data type.

If your container needs to be able to hold any arbitrary data type, I would recommend using type erasure, although that can be a bit complicated for a beginner.

3 Comments

As I commented in the previous answer, I already did a working version entirely with templates, but my teacher is now asking to scrap that, and use inheritance for the assignment, could he be a little off-focus?
@JulioCalderón If your teacher wants you to learn about inheritance.. but IMHO it's not the best example (it's one where you'd rather use templates -- the Standard container library consists of templates for this reason).
Oh ok. I guesses it wasn't the best way to use it, given that there isn't much to gain here from using it, I'll just create my own string class, given that I don't have much time to turn it in.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.