简体   繁体   中英

Private inheritance from std::basic_string

I've been trying to learn more about private inheritance and decided to create a string_t class that inherits from std::basic_string . I know a lot of you will tell me inheriting from STL classes is a bad idea and that it's better to just create global functions that accept references to instances of these classes if I want to extend their functionality. I agree, but like I said earlier, I'm trying to learn how to implement private inheritance.

This is what the class looks like so far:

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 ) );
  }
};

I get the following errors:

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>        ]

The line number (658) in the last error points to the opening brace of the split() function definition. I can get rid of the error if I comment out the using std::basic_string<value_type>::operator=; line. As I understand it, the using keyword specifies that the assignment operator is being brought from private to public scope within string_t .

Why am I getting this error and how can I fix it?

Also, my string_t class doesn't contain a single data member of it's own, much less any dynamically allocated members. So if I don't create a destructor for this class doesn't that mean that if someone were to delete an instance of string_t using a base class pointer the base class destructor would be called?

The following code throws an exception when I have a destructor defined for string_t but works when I comment out the destructor when compiled with VS2008.

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

Your default constructor should not be explicit. I think explicitness may be the reason it can't convert std::string to string_t as well, but you erased that construtor from your snippet :vP .

This program compiles and runs fine with 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;
}

You need to provide a suitable conversion constructor:

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

Otherwise the compiler doesn't know how to construct a string_t from a std::basic_string<> when you're adding elements to the vector of string_t s.

Regarding the update:
A using declaration for operator=() doesn't help if it is private. Why not just implement your own operator=() instead and forward the assignment:

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

With that it builds fine for me.

Unfortunately, you've left out enough that it's uncertain how you're getting the error message you've noted (and it doesn't help that we don't know what was line 657 when you compiled it...).

The probably currently appears to be that substr() is returning an std::string, and the compiler isn't sure how to convert that to a string_t (which is what you're asking it to store in the vector). You probably need/want to add a ctor to handle this, something like:

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

That lets the compiler know how to convert the string returned by substr() into a string_t that it can push into the vector as you requested.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM