Частное наследование от std :: basic_string - PullRequest
2 голосов
/ 08 января 2010

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

Вот как выглядит класс:

class string_t :
#if defined(UNICODE) || defined(_UNICODE)
  private std::basic_string<wchar_t>
#else
  private std::basic_string<char>
#endif
{
public:
  string_t() : basic_string<value_type>() {}

  string_t( const basic_string<value_type>& str ) 
    : basic_string<value_type>( str ) {}

  virtual ~string_t() {}

  using std::basic_string<value_type>::operator=; /* Line causing error */

  std::vector<string_t> split( const string_t& delims )
  {
    std::vector<string_t> tokens;

    tokens.push_back( substr( 0, npos ) );
  }
};

Я получаю следующие ошибки:

1>c:\program files\microsoft visual studio 9.0\vc\include\xutility(3133) : error C2243: 'type cast' : conversion from 'const string_t *' to 'const std::basic_string &' exists, but is inaccessible
1>        with
1>        [
1>            _Elem=wchar_t,
1>            _Traits=std::char_traits,
1>            _Ax=std::allocator
1>        ]

1>        c:\program files\microsoft visual studio 9.0\vc\include\xutility(3161) : see reference to function template instantiation 'void std::_Fill(_FwdIt,_FwdIt,const _Ty &)' being compiled
1>        with
1>        [
1>            _Ty=string_t,
1>            _FwdIt=string_t *
1>        ]

1>        c:\program files\microsoft visual studio 9.0\vc\include\vector(1229) : see reference to function template instantiation 'void std::fill(_FwdIt,_FwdIt,const _Ty &)' being compiled
1>        with
1>        [
1>            _Ty=string_t,
1>            _FwdIt=string_t *
1>        ]

1>        c:\program files\microsoft visual studio 9.0\vc\include\vector(1158) : while compiling class template member function 'void std::vector::_Insert_n(std::_Vector_const_iterator,unsigned int,const _Ty &)'
1>        with
1>        [
1>            _Ty=string_t,
1>            _Alloc=std::allocator
1>        ]

1>        c:\work\c++\string_t\string_t.h(658) : see reference to class template instantiation 'std::vector' being compiled
1>        with
1>        [
1>            _Ty=string_t
1>        ]

Номер строки (658) в последней ошибке указывает на открывающую фигурную скобку определения функции split(). Я могу избавиться от ошибки, если закомментирую строку using std::basic_string<value_type>::operator=;. Насколько я понимаю, ключевое слово using указывает, что оператор присваивания перемещается из области видимости private в область public в пределах string_t.

Почему я получаю эту ошибку и как ее исправить?

Кроме того, мой класс string_t не содержит ни одного собственного члена данных, тем более каких-либо динамически размещаемых членов. Так что, если я не создаю деструктор для этого класса, это не значит, что если бы кто-то delete использовал экземпляр string_t, использующий указатель базового класса, деструктор базового класса был бы вызван?

Следующий код вызывает исключение, когда у меня определен деструктор для string_t, но он работает, когда я закомментирую деструктор при компиляции с VS2008.

basic_string<wchar_t> *p = new string_t( L"Test" );
delete p;

Ответы [ 3 ]

3 голосов
/ 08 января 2010

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

Эта программа компилируется и прекрасно работает с GCC 4.2:

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

class string_t :
#if defined(UNICODE) || defined(_UNICODE)
  private std::basic_string<wchar_t>
#else
  private std::basic_string<char>
#endif
{
public:
  string_t() : basic_string<value_type>() {}

  string_t( const basic_string<value_type>& str )
    : basic_string<value_type>( str ) {}

  virtual ~string_t() {}

  using std::basic_string<value_type>::operator=; /* Line causing error */

  std::vector<string_t> split( const string_t& delims )
  {
    std::vector<string_t> tokens;

    for ( size_t pen = 0, next = 0; next != npos; pen = next + 1 ) {
        next = find_first_of( delims, pen );
        if ( pen != next ) tokens.push_back( substr( pen, next - pen ) );
    }
    return tokens;
  }

  template<class os>
  friend os &operator<<(os &, string_t const&);
};

template< class os_t >
os_t &operator<<( os_t &os, string_t const &str ) {
        return os << static_cast< string >(str);
}

int main( int argc, char ** argv ) {
        vector<string_t> mytoks = string_t( argv[1] ).split( string( "_" ) );

        for ( vector<string_t>::iterator it = mytoks.begin(); it != mytoks.end(); ++ it ) {
                cerr << * it << endl;
        }
        return 0;
}
2 голосов
/ 08 января 2010

Вам необходимо предоставить подходящий конструктор преобразования:

 string_t(const std::basic_string<value_type>&);

В противном случае компилятор не знает, как создать string_t из std::basic_string<>, когда вы добавляете элементы в вектор string_t s.

По поводу обновления:
Объявление using для operator=() не помогает, если оно закрытое. Почему бы просто не реализовать вместо этого свой собственный operator=() и передать задание:

string_t& operator=(const string_t& s) 
{
    basic_string<value_type>::operator=(s); 
    return *this; 
}

При том, что это прекрасно для меня.

0 голосов
/ 08 января 2010

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

Вероятно, в настоящее время, похоже, substr() возвращает std :: string, и компилятор не уверен, как преобразовать это в string_t (что вы и просите сохранить в вектор). Вы, вероятно, должны / хотите добавить ctor для обработки этого, что-то вроде:

string_t(std::string const &init) : std::string(init) {}

Это позволяет компилятору знать, как преобразовать строку, возвращаемую substr(), в string_t, которую он может вставить в вектор по вашему запросу.

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