c++ 无法创建仅导致“语法糖”的std::string的 Package 器

svgewumm  于 2023-07-01  发布在  其他
关注(0)|答案(2)|浏览(181)

我知道std::string is not designed for inheritance,但是,我想知道为什么这个类定义不能编译:

using std::string;
class ExtendedString: public string
{
public:
    using string::string;
    ExtendedString left(size_type n) const {
        return substr(0, n>size()?size():n);
    }
};

我得到这个错误:

../../src/capel-tool.cpp:21:17: error: could not convert ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::substr(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type) const [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int](0, ((n > ((const ExtendedString*)this)->ExtendedString::<anonymous>.std::__cxx11::basic_string<char>::size()) ? ((const ExtendedString*)this)->ExtendedString::<anonymous>.std::__cxx11::basic_string<char>::size() : n))’ from ‘std::__cxx11::basic_string<char>’ to ‘ExtendedString’

我期望left函数使用std::string中的任何默认构造函数。
即使我像这样添加一个显式的构造函数:

using std::string;
class ExtendedString: public string
{
public:
    using string::string;
    ExtendedString left(size_type n) const {
        return substr(0, n>size()?size():n);
    }

    explicit ExtendedString(const std::string &s);
};

我仍然得到同样的错误。
只有当我添加一个普通构造函数时:

using std::string;
class ExtendedString: public string
{
public:
    using string::string;
    ExtendedString(const std::string &s);
    ExtendedString left(size_type n) const {
        return substr(0, n>size()?size():n);
    }
};

代码编译OK。
现在假设我想对一个为继承而设计的类做同样的事情。我能不能只创建这种 Package 器的方式,类可以互换使用,而不需要创建构造函数,而将创建和调用,而不仅仅是“语法糖”

编辑1:

这个suggested question确实解释了为什么我的代码不起作用,但它并没有像公认的问题那样提出任何替代方案。

ne5o7dgx

ne5o7dgx1#

代码的问题是substr返回std::string,而不是ExtendedString。类型之间不存在隐式转换,因此无法编译return语句。在继承层次结构中有一个隐式转换,即您可以将ExtendedString转换为std::string,但不能反过来。
要解决这个问题,只需使用left函数:

  • 你可以使构造函数隐式:ExtendedString(const std::string&)
  • 明确构建:return ExtendedString(substr(...))

然而,一般来说,你试图做的事情在C中是不可能的。从std::string继承的每个成员函数都不会返回ExtendedString,所以你有错误的接口。C没有给你定义 * 扩展方法 * 的方法,这是你模仿的特性。

“Clean” 可选

  • 创建从std::stringExtendedString的隐式转换,但这会导致不必要的复制
  • 注意:这是你在声明ExtendedString(const std::string &s);时所做的
  • std::string私有继承,或者更好,将其 Package 为成员
  • std::string拥有的每个成员函数创建 Package 器函数,并使它们在必要时接受/返回ExtendedString
  • 只创建自由函数(见下文)
std::string left(const std::string& s, std::size_t n) {
    return s.substr(0, std::min(s.size(), n));
}

尽管有时调用str.function()有时调用function(str)很烦人,但与任何替代方案相比,这种不一致性的代价很小。

qnyhuwrf

qnyhuwrf2#

class ExtendedString
{
private:
    std::string data_;

public:
    ExtendedString() = default;
    ExtendedString(const std::string& s) : data_(s) {}

    ExtendedString left(std::string::size_type n) const {
        return ExtendedString(data_.substr(0, n > data_.size() ? data_.size() : n));
    }

    // Forward other methods as needed
};

相关问题