来自 std::basic_string 的私有继承

发布于 2024-08-17 07:49:34 字数 2971 浏览 1 评论 0原文

我一直在尝试了解有关私有继承的更多信息,并决定创建一个继承自 std::basic_stringstring_t 类。我知道很多人会告诉我从 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::operator=; 行,我可以消除该错误。据我了解,using关键字指定赋值运算符在string_tprivate范围带到public范围>。

为什么我会收到此错误以及如何修复它?

另外,我的 string_t 类不包含它自己的单个数据成员,更不用说任何动态分配的成员了。因此,如果我不为此类创建析构函数,并不意味着如果有人使用基类指针删除 string_t 的实例,则基类析构函数会被称为?

当我为 string_t 定义析构函数时,以下代码会引发异常,但当我在使用 VS2008 编译时注释掉该析构函数时,以下代码会正常工作。

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

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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

⒈起吃苦の倖褔 2024-08-24 07:49:35

不幸的是,你已经遗漏了足够多的内容,以至于不确定你如何获得你所注意到的错误消息(而且我们不知道你编译它时第 657 行是什么,这并没有帮助......)。

当前可能出现的是 substr() 返回 std::string,并且编译器不确定如何将其转换为 string_t (这就是你要求它存储在向量中)。您可能需要/想要添加一个 ctor 来处理此问题,例如:

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

这让编译器知道如何将 substr() 返回的字符串转换为 string_t可以按您的要求推入向量。

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.

半世晨晓 2024-08-24 07:49:34

您的默认构造函数不应是显式的。我认为明确性可能是它无法将 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;
}

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;
}
梅倚清风 2024-08-24 07:49:34

您需要提供合适的转换构造函数:

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

否则,当您添加元素时,编译器不知道如何从 std::basic_string<> 构造 string_t到 string_t 的向量。

关于更新:
如果 operator=() 是私有的,则 using 声明没有任何帮助。为什么不直接实现您自己的 operator=() 并转发分配:

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

这样它就适合我了。

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_ts.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文