2013-06-26 2 views
1

В настоящее время я работаю над проектом колледжа с C++, и одним из моих заданий является создание социальной сети с использованием наследования и полиморфизма. В настоящее время у меня есть класс Node, который используется на . Карта и Multimap (оба создаются вручную и не используются с std). Узел может содержать две переменные (например, ) и данные), и где я его использую, первая переменная может быть указателем или строкой (они позволяют нам использовать std :: string).Как использовать std :: string с наследованием в качестве параметра?

Проблема, с которой я сталкиваюсь, заключается в том, что когда я наследую класс «root» (Object Object) и использую «Object» в качестве типа данных для «ключа», я не могу передать строку, созданную с помощью std как параметр к его конструктору, потому что он не наследуется от моего класса Object. Одно из решений - реализовать мой собственный класс строк и сделать его унаследованным от Object, но я искал другие обходные пути.

Если у вас возникли проблемы с логикой выше, скажите мне, что я только начинаю с C++.

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

Строковых или Person типа в настоящее время используется только в ключе, но это с другой реализацией с использованием шаблонов (который работает отлично), но мой учитель теперь требует от нас применить наследование ко всему проекту (привыкнуть к нему, я думаю).

+2

Пожалуйста, используйте примерный код, чтобы показать, что вы сейчас пытаетесь, даже если вы знаете, что это неправильно. – aschepler

+0

Вы можете обернуть 'std :: string' в некоторый класс, полученный из' Object', поэтому это возможно. – dyp

+0

@aschepler Я добавил свой класс Node и еще несколько объяснений. –

ответ

1

Чтобы реализовать это с помощью наследования, вы думаете о Key как тип данных, специально разработанный как ключ в реализации вашей карты/мультимапа. Key наследует от Object, но он может предоставлять свои собственные ключевые функции, такие как –, например –, функцию repr(), которая генерирует представление, используемое картой для некоторых операций с определенными картами (возможно, в качестве основы для хэширования или сортировки или что-то еще).

Карта/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 в двух производных классов, 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_; 
}; 

Когда вы делаете вставки в вашей карте/Multimap, вы создаете 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, который не является на самом деле необходимо, чтобы решить вашу проблему.)

+0

Спасибо! Это похоже на лучший способ его реализации. –

0

Я думаю, что вы действительно ищете шаблоны. Ваше решение с «корневым объектом» не будет работать, как вы можете видеть со стандартными объектами и внешними библиотеками, но также вы не сможете использовать свои контейнеры с примитивами (например, id лица (как int) в качестве ключа, а класс Person as стоимость).

С помощью шаблонов вы можете указать, с каким типом вы будете работать во время компиляции, и компилятор поможет вам соблюдать ваши собственные правила. Он может быть объявлен как это:

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

Затем вы можете использовать его более или менее, как это:

Map<std::String, int> phoneBook; 

И компилятор будет охранять вас и предупредить, если вы пытаетесь добавить, например, плавать вместо of int, вам Карта. Но прежде чем начинать кодирование, я советую вам сначала прочитать некоторые уроки или, возможно, даже книгу на C++ в целом. Но если вы хотите начать с родовым прямо сейчас, вы можете начать ее:

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

+0

О, я уже реализовал весь проект, используя шаблоны для Map, Multimap, Node и Graph, но теперь назначение состоит в использовании наследования. –

0

Единственным способом был бы в состоянии хранить строку в переменной Object был, если строка класс наследуется от вашего объекта класс, поэтому к сожалению, вам придется реализовать свой собственный класс String.

Настоящий недостаток заключается в том, что вы используете подход Java/C# для проектирования, где переменная Object может содержать что угодно. В C++ надлежащим способом обработки таких вещей является использование шаблонов, предполагая, что ваш Map/Multimap/Node должен содержать только один конкретный тип данных.

Если ваш контейнер должен иметь возможность хранить произвольный тип данных, я бы рекомендовал использовать стирание типа, хотя это может быть немного сложным для новичка.

+0

Как я уже отмечал в предыдущем ответе, я уже сделал рабочую версию полностью с шаблонами, но мой учитель теперь просит отказаться от этого и использовать наследование для задания, может ли он быть немного не в фокусе? –

+0

@ JulioCalderón Если ваш учитель хочет, чтобы вы узнали о наследовании .., но ИМХО это не лучший пример (это тот, где вы предпочитаете использовать шаблоны - стандартная контейнерная библиотека состоит из шаблонов по этой причине). – dyp

+0

О, я думаю, это был не лучший способ используйте его, учитывая, что от его использования не так много, я просто создаю свой собственный класс строк, учитывая, что у меня мало времени, чтобы его включить. –