2015-08-06 2 views
0

Я хочу добавить новую функцию-член «charReplace» в класс строк. Функция заменит все события одного символа другим символом. Поэтому я подготовил образец кода.Как добавить функции-члены в встроенные классы в C++?

#include <iostream> 
#include <string> 

std::string string::charReplace(char c1, char c2) { //error in this line 
    while(this->find(c1) != std::string::npos) { 
     int c1pos = this->find(c1); //find the position of c1 
     this->replace(c1pos, 1, c2); //replace c1 with c2 
    } 
    return *this; 
} 

int main() { 
    std::string s = "sample string"; 

    s.charReplace('s', 'm') /* replace all s with m */ 

    std::cout << s << std::endl; 
} 

Но это не работает. При компиляции я получаю следующую ошибку в строке 4.

error: 'string' does not name a type

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

P.S. Я все еще новичок в C++. Я использую его только на несколько месяцев. Поэтому, пожалуйста, постарайтесь сделать ваш ответ понятным.

+1

Однако это все еще не работает, потому что вы не можете/не должны редактировать заголовок строки. Поэтому после добавления std ::, itll все еще жалуется на функцию, но теперь, когда она не является частью строки. –

+1

Вот лучший способ: [Как заменить все символы символа - строка] (http://stackoverflow.com/questions/2896600/how-to-replace-all-occurrences-of-a-character-in -string) –

+0

string - довольно сложная структура (typedef basic_string , allocator > string;) ... я бы предложил вам определить новый класс, содержащий строку, и новую функцию charReplace – Zohar81

ответ

6

Вы не можете. это C++, а не JavaScript (где вы можете прототипировать любые классы).

ваши варианты:

  1. наследование
  2. состав
  3. стоящие функции
+0

Наследование - худший вариант здесь. Большинство стандартных классов C++ не предназначены для унаследованных. –

+0

список не имеет логики в заказе –

+0

Но это подразумевает (по крайней мере, для меня), что они одинаково хороши. –

0

Вы не можете (и не должны) изменять класс std::string (в частности, поскольку он стандартизован на C++ 11 и предоставляется его стандартной библиотекой).

Вы можете подкласса std::string (но это часто встревожено).

0

Вы не можете "добавить" функции к уже определенному классу.

Что вы можете сделать, это сделать самостоятельные функции, называется charReplace

+1

Или используйте 'std :: replace' :-) –

0

Там нет никакого способа сделать добавления методов в существующие классы в C++, если вы непосредственно не изменить их определение (которые вы не должны делать с стандартные классы).

Таким образом, вы ограничены двумя вариантами:

  • подклассов: Это не рекомендуется для стандартных библиотек классов, если вы не знаете, что вы делаете. (Если вам нужно спросить, вы, вероятно, нет. Виртуальные деструкторы E.G. являются важным моментом здесь.)
  • Добавление бесплатных функций (или статических функций класса): в вашем случае это будет std::string charReplace(std::string& str, char c1, char c2){...};, называемый charReplace(s,c1,c2). Это единственный возможный вариант.
+0

*« Виртуальные деструкторы E.G. здесь важны »* - Нет, это не так. Вывод из 'std :: string' был бы достаточно плохим, добавление виртуального деструктора еще больше ухудшало бы ситуацию. –

+0

Возможно, вы имеете в виду попытку удалить «std :: string» полиморфно, если у него нет виртуального деструктора. Это, конечно, верно, но добавление виртуального деструктора в ваш производный класс не исправит его. Он должен быть в базовом классе. Так что вы ничего не можете с этим поделать. –

+0

@ChristianHackl Я никогда не говорил, что * добавление * виртуальных деструкторов важно. * Знание достаточно о них, однако. (Например, почему вы не захотите добавить его или назначить объект производного класса «string *» и удалить его.) – anderas

1

ошибка точка сообщения этого идентификатор

std::string string::charReplace(char c1, char c2) { 
      ^^^^^^ 

, неизвестно компилятор. Компилятор знает только std::string, но он не знает, что означает неквалифицированный идентификатор string.

Но в любом случае подход неверен, поскольку все члены класса должны быть объявлены в определении класса. Вы не можете добавлять новых членов класса без изменения его определения.

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

Примите во внимание, что в вашей реализации функции имеется серьезная ошибка. Если аргументы c1 и c2 указывают один и тот же символ, то функция будет иметь бесконечный цикл.

Я бы записать функцию следующим образом

std::string & charReplace(std::string &s, char c1, char c2) 
{ 
    for (std::string::size_type pos = 0; 
      (pos = s.find(c1, pos)) != std::string::npos; 
      ++pos) 
    { 
     s[pos] = c2; 
    } 

    return s; 
} 
+1

для (char & c: s) if (c == c1) c = c2; – qPCR4vir

2

Вы не можете добавить к интерфейсу std::string, но вы можете сделать это:

#include <string> 
#include <iostream> 
#include <algorithm> 

int main() 
{ 
    std::string s = "sample string"; 

    std::replace(s.begin(), s.end(), 's', 'm'); /* replace all s with m */ 

    std::cout << s << std::endl; 
} 

Выход:

mample mtring 
0

But I want to do it using a member function. So, is there a way to do this in c++?

No.

Однако настоящий вопрос должен быть: Почему?

std::string раздувается достаточно, как есть. Настолько, что Херб Саттер однажды написал об этом GotW article.

В C++ очень хорошая практика расширить функциональность класса за счет самостоятельных функций, отличных от друга. Это значительно улучшает инкапсуляцию, потому что автономная функция, отличная от друга, не может получить доступ к элементам private или protected.

Если вы посмотрите на стандартную библиотеку или библиотеки Boost, вы обнаружите, что этот принцип применяется много. На ней основана вся «STL» (= контейнеры/алгоритмы/итераторы), входящая в стандартную библиотеку. Публичные интерфейсы классов контейнеров, такие как std::set или std::vector, не имеют таких функций, как reverse, count_if или all_of. Есть свободно стоящие функции для этого:

Вы должны следовать этому отличный пример в C++, а не работать против него ,


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

Why should one not derive from c++ std string class?

Наконец, следует отметить, что такого рода рассмотрение не является уникальным для C++. Возьмите Java, например. В Java лучше всего получить только из классов, которые предназначены для базовых классов.Это даже предмет в знаменитой книге «Эффективная Ява» Джошуа Блоха. В случае класса Java String вы, конечно, не могли бы извлечь из этого, потому что это final. Скорее всего, если бы сегодня была разработана стандартная библиотека C++, а новые функции, добавленные в C++ 11, std::string тоже были бы final (хотя Бьярн Страуструп, изобретатель C++, по-видимому, никогда не был большим поклонником финальных классов , но это еще одна история).

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