оператор перегрузки. - PullRequest
       2

оператор перегрузки.

3 голосов
/ 18 октября 2011

Хорошо, я знаю, что operator. не перегружается, но мне нужно что-то подобное.

У меня есть класс MyClass, который косвенно встраивает (имеет) std::string и должен вести себя точнокак std::string, но, к сожалению, не может расширяться std::string.

Есть идеи, как этого добиться?

Редактировать : я хочу, чтобы строки ниже компилировались нормально

MyClass strHello1 ("Привет слово");

std :: string strValue = strHello1;
const char * charValue = strHello1.c_str ();

Ответы [ 6 ]

1 голос
/ 19 октября 2011

Пытаясь подвести итоги всех обсуждений, похоже, что вы никогда не найдете подходящего решения, потому что ... ваши требования находятся в предубеждении.

  1. Вы хотите, чтобы ваш класс вел себя как ats:: string
  2. std :: string ведет себя как значение, но
  3. значение не «изменяется» при доступе, но (подумайте, c = a + b: ожидаете ли вы изменения a и bих значение ??) ...
  4. при доступе к вашему "значению" вы хотите изменить его.

Если что-то я подвел, собирая все миры (предложение: отредактируйте свой вопросв противном случае все отвечающие рискуют быть потерянными) правильно, у вас проблемы с 3 и 4 (обратите внимание, что 3. происходит от понятия «назначение», и вы можете не замечать его, в то время как 4. приходит от вас напрямую).)

Теперь я могу попытаться перепроектировать вашу психологию (потому что вы не предоставили хорошую информацию о том, что представляет ваш класс и почему вы не можете «расширить» строку), я не могу найти две возможности, ни одну из которыхбудет соответствовать всемвышеуказанные требования.

  1. Сохраните строку в своем классе и заставьте ваш класс вести себя как std :: string.Есть три способа прийти к этой точке:

    a.вставьте строку и заставьте ваш класс распадаться на нее: по сути, ваш класс должен содержать

.

operator std::string&() { return my_string; } //will allow l-value assignments
operator const std::string&() const { return my_string; } //will allow r-value usage
const char* c_str() const { return my_string.c_str(); }

b.происходит от std :: string.Фактически это похоже на наличие анонимной строки my_string, которая подразумевает «распад» операций.Не так, как указано выше.

c.Внедрить или получить в частном порядке, и переписать интерфейс std :: string, делегируя функции std :: string.Это просто долгий набор текста, чтобы получить именно b.результат.так что, черт возьми?(этот последний вопрос посвящен всем тем, кто считает, что a или b нарушат инкапсуляцию. c также нарушит его, это займет больше времени!)

  1. Не хранитьСтрока, но просто получите ее в результате вычисления («поиска», о котором вы говорите, не уточняя, что это такое).

В этом последнем случае вам нужен класс с затуханиемавтоматически в std :: string как значение.Поэтому в вашем классе

operator std::string() const { return your_lookup_here; }

необходимо отметить, что const необходим, но нет необходимости изменять внутреннее состояние вашего класса, поскольку результирующая строка не сохраняется.

Но этопоследнее решение имеет проблему с const char *: поскольку строка является временной, пока вы ее не назначите, ее буфер также является временным (будет уничтожен), поэтому распад на const char * для назначения указателя не имеет смысла (указательбудет указывать на мертвый буфер).У вас может быть

const char* c_str() const { return std::string(*this).c_str(); } //will call the previous one

, но вы можете использовать его только в выражениях или сквозном параметре в вызовах функций (так как временное будет существовать, пока вычисляющее выражение не будет полностью оценено), а не в присваиваниизначение l (например, const char* p; p = myclassinstace.c_str();)

Во всех вышеперечисленных случаях (все 1.) вам также необходимо:

 myclass() {}
 myclass(const std::string& s) :my_string(s) { ... }
 myclass(const char* s) :my_string(s) { ... }

или - в C ++ 11 просто

template<class ...Args>
myclass(Args&&... args) :my_string(std::forward<Args...>(args...)) {}

В случае 2. вместо инициализации несуществующего my_sting, вы должны использовать аргументы, чтобы установить, что вы будете искать (мы не знаем, что это такое, так как вы не сказали нам)

Надеюсь, что во всех этих опциях вы найдете что-то полезное.

1 голос
/ 18 октября 2011

Вы можете расширить интерфейс без publically наследования от него.Это предотвращает случай проблемного полиморфного разрушения (иначе говоря, не виртуальный деструктор):

#include <iostream>
#include <string>
using namespace std;

class MyClass
   : private std::string
{
public:
   MyClass(const char* in)
      : std::string(in)
   {}

   // expose any parts of the interface you need
   // as publically accessible
   using std::string::c_str;
   using std::string::operator+=;
};

int main()
{
   MyClass c("Hello World");

   cout << c.c_str() << "\n";

   c += "!";

   cout << c.c_str() << "\n";

   // Using private inheritance prevents casting, so 
   // it's not possible (easily, that is) to get a 
   // base class pointer

   //  MyClass* c2 = new MyClass("Doesn't work");
   // this next line will give a compile error 
   //  std::string* pstr = static_cast<MyClass*>(c2);
   // delete c2;
}
1 голос
/ 18 октября 2011

Согласно вашему последующему редактированию, это:

MyClass strHello1("Hello word");

std::string strValue = strHello1;
const charValue = strHello1.c_str();

должно скомпилироваться нормально, единственное решение - написать обертку над std::string:

class MyClass
{
private:
   std::string _str;
public:
   MyClass(const char*);
   //... all other constructors of string

   operator std::string& ();
   //... all other operators of string

   const char* c_str();
   //... all other methods of string

   friend std::string& operator + ( std::string str, Foo f);
};

//+ operator, you can add 2 strings
std::string& operator + ( std::string str, Foo f);

Однако это утомительная работа и должна быть тщательно проверена. Желаем удачи!

1 голос
/ 18 октября 2011

Если вас не интересует полиморфное удаление строки *, вы можете получить ее из std :: string, просто получая поведение вашего класса "as-a" std :: string. Не больше, не меньше.

Литания ", которую вы не можете получить из классов, у которых нет виртуального деструктора " (если вы говорите, что не можете его расширять), это как "dont use goto", "dont ' используйте do-while "" не многократный возврат "" не используйте ту или иную функцию ".

Все хорошие рекомендации от и для людей, которые не знают, что делают .

std::string не имеет виртуального деструктора, поэтому не присваивайте new yourcalss std::string*. Вот и все.

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

1 голос
/ 18 октября 2011

Вы можете перегрузить оператор преобразования , чтобы неявно преобразовать его в std::string:

class MyClass
{
    std::string m_string;
public:
    operator std::string& ()
    {
        return m_string;
    }
};
0 голосов
/ 18 октября 2011

Вы можете добавить ссылку на оператор const в строку следующим образом:

class C
{
public:
  // Implicit conversion to const reference to string (not advised)
  operator const std::string &() const
  {
    return s_;
  }

  // Explicit conversion to a const reference to string (much better)
  const std::string &AsString() const
  {
    return s_;
  }

private:
  std::string s_;
};

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

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