Конструктор не работает для класса, унаследованного от std :: string - PullRequest
5 голосов
/ 17 февраля 2009

при выполнении

#include <string>

class MyString : public std::string 
{
 public:    
   MyString() {}
};

Но использование ниже:

MyString s = "Happy day";
MyString s("Happy Day");
MyString s = (MyString)"Happy day";

ни один из них не работает.

Кажется, что-то связано с объявлением / переопределением конструкторов / операторов, но может ли кто-нибудь помочь указать, где я могу найти эти ресурсы?

Спасибо.

Ответы [ 6 ]

35 голосов
/ 17 февраля 2009

std::string не предназначен для наследования. Он не имеет каких-либо виртуальных функций (даже деструктора!), Поэтому вы не можете ничего переопределить. Он также не имеет защищенного интерфейса, поэтому вы ничего не получите от подклассов, чего не могли бы получить, создав некоторые автономные служебные функции, которые принимают std::string.

Имейте в виду, что большинство реализаций STL ожидают, что вы будете использовать std::string с семантикой копирования, а не со ссылочной семантикой, и это делает случай добавления унаследованных полей или переопределяющих функций еще слабее.

Если вы действительно хотите что-то наподобие std::string с дополнительными функциями, вы можете рассмотреть возможность использования композиции вместо наследования, но это тоже не очень хорошо. Вам не нужно беспокоиться о том, что деструктор std::string не будет вызван должным образом, но в конечном итоге вам придется обернуть множество нужных вам методов из std::string, что утомительно. Кроме того, ваши служебные функции будут работать с MyString только тогда, когда большая часть кода будет ожидать std::string, поэтому он не очень многократно используется.

Вам лучше сделать некоторые служебные функции, которые принимают std::string. Или, если std::string не обеспечивает то, что вам нужно, вы должны использовать другую строковую реализацию, которая соответствует вашим потребностям. Вот некоторые возможности, которые приходят на ум:

6 голосов
/ 17 февраля 2009

Вам нужно определить несколько конструкторов для разных типов, которые вы хотите иметь возможность преобразовывать в ваши строки. Эти конструкторы могут просто передавать параметры в базовый std::string.

Если вы не создадите их вручную, компилятор создаст для вас конструктор по умолчанию и конструктор копирования:

MyString() : std::string() { }
MyString(const MyString &other) : std::string(other) { }

Чтобы разрешить построение из строковых литералов, вам нужен конструктор, который принимает const char*:

MyString(const char* other) : std::string(other) { }

Конструктор, который принимает const std::string&, также будет полезен для преобразования std::string s в ваш строковый тип. Если вы хотите избежать неявных преобразований обычных строк, вы должны сделать это explicit:

explicit MyString(const std::string &other) : std::string(other) { }

(отредактировано, поскольку в моей исходной версии было много ошибок, и я не могу удалить принятый ответ)

4 голосов
/ 20 февраля 2009

Суть в том, что вы не должны этого делать. Деструктор на std::string не является виртуальным. Это означает, что если вы делаете следующее:

std::vector<std::string*> s_vector;
s_vector.push_back(new MyString("Hello"));
s_vector.push_back(new std::string("World"));

const std::vector<std::string*>::iterator s_vector_end = s_vector.end();
std::vector<std::string*>::iterator s = s_vector.begin();
for (; s != s_vector_end; ++s)
{
    delete *s; // Error, MyString's destructor will
               // not be called, but std::string's!
}

Единственный способ, которым это может быть безопасно, - это если вы не добавляете членов в свою строку. Вы можете подумать, что вам это не нужно сейчас, но кто-то, кто не знает об этой проблеме, может прийти позже (или вы, возможно, когда вы забыли этот совет) и добавить один, а затем, эй presto, у вас трудно отследить утечку памяти.

3 голосов
/ 17 февраля 2009

std :: string не предназначен для наследования. У него нет виртуальных методов, поэтому вы не можете переопределить ни один из его методов.

Вы должны посмотреть на композицию. Или просто создавая служебные функции, которые работают с std :: strings

3 голосов
/ 17 февраля 2009

Проблема в том, что вам нужно перегрузить конструктор, который принимает const char *, и вызвать конструктор базового класса следующим образом:

class MyString : public std::string {
   public:    
      MyString() {}
      MyString( const char* c ) : std::string( c )  {}
};

Тогда все три теста должны сработать.

1 голос
/ 17 февраля 2009

Вы определяете ctor MyString, который не принимает аргументов. Если переопределяет другие ctors, значит, ctor не принимает строковый аргумент вообще.

Вам нужно ctor одного аргумента типа const char *, что-то вроде

 MyString(const char * s): std::string(s){}

(Не доверяйте синтаксису, посмотрите его; я больше не пишу на С ++ каждый день.)

Проверьте раздел в C ++ FAQ Lite о ctors .

(Упс. Const char *, а не string. Сказал, что я не пишу C ++ каждый день.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...