1

Я хочу расширить std::string с некоторой функциональностью, поэтому я получаю свой String от него. Чтобы сделать код вроде String str = stdStr;, я попытался перегрузить оператор присваивания, но по какой-то причине мой код не вызывается. Как я могу это исправить?Перегрузка оператора присваивания C++

#include <string> 

class String 
    : 
     public std::string 
{ 

    public: 
     /* 
     I do know that this constructor will solve the problem, but is it possible to use the operator? 

     String (const std::string& stdString) 
     { 

      ... 

     } 
     */ 

     String& operator= (const std::string& stdString) 
     { 
      ... 
      return *this; 
     } 

}; 

int main() 
{ 

    std::string foo = "foo"; 
    String bar = foo; 

    return 1; 

} 
+2

Вы уверены, что наследование - это правильный способ расширения? –

+1

Я думаю, что расширение строки - плохая идея. Невозможно сказать, какова ваша новая функциональность, но могу с уверенностью сказать, что наследование - это не способ сделать это. – duffymo

+0

Хуже всего то, что вы называете это 'String' – UmNyobe

ответ

10
String bar = foo; 

Это инициализация копия (равносильно

String bar(String(foo)); 

), а не назначение. Вы должны реализовать конструктор копирования для этих работ (или инициализировать переменную по умолчанию, а затем назначить foo на bar).

В любом случае, это плохая идея для получения стандартных типов C++, поскольку эти типы не имеют виртуальных деструкторов. И состав еще лучше, чем наследование, в вашем примере вы должны использовать композицию.

+0

Благодарим вас за ответ. Является ли лучшей идеей сделать 'std :: string' членом моей« String »и, таким образом, расширить ее функциональность? – Kolyunya

+0

Да, это определенно лучше сделать std :: string членом String. – riv

+1

@ Kolyunya: Тот факт, что thre не является виртуальным dtor, является очень слабым аргументом. Строка ** ЦЕННОСТИ **. Они никогда не будут назначены 'new' в направлении' std :: string * 'и будут удалены как таковые. Правильно используемые 'string'-s и' String'-s не будут страдать от какого-либо UB. 'String'-s (а также' string', ar не объекты OOP, поэтому правила OOP не должны применяться здесь: вместо этого должны применяться правила арифметики VALUE) –

9

Линия String bar = foo Это не присвоение, это фактически эквивалент String bar(foo). Если вы напишете

String bar; 
bar = foo; 

Ваш оператор назначения будет называться, как и ожидалось.

+0

Ничего себе, это сложно! Благодаря! – Kolyunya

+0

Они на самом деле не эквивалентны. Один из них является прямым, другой - инициализацией. –

+0

Несомненно, есть некоторые тонкие различия, как в http://stackoverflow.com/questions/1051379/ - но в этом случае они не применяются. – riv

1

В вашем случае, despte = настоящее, новый строковый объект будет создан, таким образом, требует

String (const std::string& stdString) 

быть раскомментированы. Другим вариантом было бы сделать что-то вроде

String bar; 
bar = foo; 

, но это не звучит как хорошая идея.

6

Проблема здесь состоит в том, что вашей линии

String bar = foo; 

не вызывает оператор присваивания, потому что у вас нет объекта для назначения (bar еще не создан); он вызывает конструктор. В самом деле, он будет вызывать ваш конструктор комментариев, если он будет доступен.

Если вы действительно хотите использовать оператор, вы должны написать:

String bar; 
bar = foo; // Now bar exists and you can assign to it 

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

std::string* str = new String(); 
delete str; // Oops; the wrong destructor will be called 
+1

Технически corred но ... Может ли кто-то из «не выводить» школьные филиалы tellmy, для какой причины ... нужно использовать полиморфизм строк? Мне 30 лет я программирую, и я никогда не видел «std :: string» str = new String(); 'в моей старой жизни от любых пользователей производных классов. –

+2

@EmilioGaravaglia: Это вопрос «расстояния до возможной ошибки». Получение класса, не имеющего виртуального деструктора, само по себе не является ошибкой, но наличие такого класса приводит к тому, что ваш клиент * ближе * к ошибке, потому что теперь вы должны * документировать * эту особенность поведения. И мы все знаем, насколько вероятно, что это произойдет. (И письмо, и чтение.) Для новичков вы обычно даете общий совет, и на этот раз он «не распространяет стандартные классы». – DevSolar

+0

@EmilioGaravaglia Добавляя к тому, что говорит DevSolar, эта строка может быть маловероятной, но передача «String *» в функцию, принимающая 'std :: string *', не является. Передача ссылок также приводит к полиморфному поведению, хотя я признаю, что вы не захотите удалить объект, полученный по ссылке. Конечно, если вы знаете опасность, вы можете принять меры против нее (например: принудительно использовать «String» вместо 'std :: string' в вашем коде), но опасность все еще существует. – Gorpik

1

Выполнение этого использует конструктор копирования:

String foo("foo"); 
String foo="hello";//assignment operator here 

Но это не делает:

String foo; 
String foo="hello";//copy constructor used here since foo was not initialized 
1

Другие одобренные ответы хорошо информированы.

В интересах прямого ответа на ваш вопрос вы пытаетесь это сделать.

String& operator= (const std::string& stdString) 
    { 
     // Call the base implementation 
     return std::string::operator= (stdString); 
    } 
1

std :: string foo = "foo"; Строка bar = foo;

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

Его лучше избегать наследования std :: string, поскольку он не определяет виртуальный деструктор.

Смежные вопросы