不能在 std::string 周围创建一个只导致“语法糖”的包装器

Can not create a wrapper around std::string that results in only "syntax sugar"

提问人:Santilín 提问时间:6/25/2023 最后编辑:Santilín 更新时间:6/25/2023 访问量:101

问:

我知道 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);
    }
};

我收到此错误:

../../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’

我希望该函数将使用 std::string 中的任何默认构造函数。left

即使我添加一个显式构造函数,如下所示:

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

代码编译正常。

现在想象一下,我想用一个为继承而设计的类做同样的事情。我不能只是以一种可以互换使用的方式创建这种包装器,而无需创建构造函数,而是可以创建和调用构造函数,而不仅仅是“语法糖”

编辑1:

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

C++ 继承 stdstring

评论

2赞 Ted Lyngmo 6/25/2023
如果您使用它,该版本应该可以工作:explicitreturn ExtendedString{substr(0, n>size()?size():n)};
3赞 Eljay 6/25/2023
需要显式调用显式构造函数。如果您正在尝试扩展方法之类的方法,我建议使用包装器结构或独立函数。(C++23 还有另一个不错的替代方案,如果你可以使用它的话。
1赞 Nelfeal 6/25/2023
这回答了你的问题吗?为什么“继承的构造函数不是从相同或派生类型的表达式初始化的候选对象”?
1赞 n. m. could be an AI 6/25/2023
如果一个类是为继承而设计的,那么它可能不是为复制而设计的。

答:

5赞 Jan Schultke 6/25/2023 #1

您的代码的问题在于返回 ,而不是 .类型之间不存在隐式转换,因此无法编译 return 语句。 在继承层次结构中有一个隐式转换,即您可以转换为 ,但不能转换为 。substrstd::stringExtendedStringExtendedStringstd::string

要仅针对您的函数解决此问题:left

  • 您可以隐式构造函数:ExtendedString(const std::string&)
  • 显式构造:return ExtendedString(substr(...))

但是,一般来说,您尝试执行的操作在 C++ 中是不可能的。您继承的每个成员函数都不会返回,因此您有错误的接口。C++ 无法定义扩展方法,而扩展方法正是您正在模仿的功能。std::stringExtendedString

“干净”选择

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

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

-2赞 Chloe Harper 6/25/2023 #2
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
};

评论

0赞 Santilín 6/25/2023
Thaks 的回复。它的问题是构造函数中有 s 的副本,所以这不是语法糖。另一个问题是我必须从 std::string 中实现许多方法,我希望编译器为我做到这一点。
0赞 Chloe Harper 6/25/2023
@Santilín 我理解你的担忧。如果要避免不必要的复制,并尽量减少手动实现方法,可以考虑使用其他方法。您可以创建一个包装类,而不是继承 ,该包装类包含指向其接口的引用或指针,并提供其接口的子集。ExtendedString(const std::string& s) : str_(s) {} ExtendedString left(std::string::size_type n) const { return ExtendedString(str_.substr(0, n > str_.size() ? str_.size() : n));std::stringstd::stringstd::string
1赞 NotTheDr01ds 6/27/2023
欢迎来到 Stack Overflow!您(目前)的 19 个答案中的大部分或全部(以及您的大多数评论回复)似乎可能全部或部分由 AI(例如 ChatGPT)编写,到目前为止,我检查过的太多答案似乎存在错误,这些错误已在评论中指出。请注意,此处禁止发布 AI 生成的内容。如果您使用 AI 工具来协助回答任何问题,我鼓励您将其删除。谢谢!
1赞 NotTheDr01ds 6/27/2023
读者应该仔细和批判性地审查这个答案,因为人工智能生成的信息通常包含根本性的错误和错误信息。如果您发现质量问题和/或有理由相信此答案是由 AI 生成的,请留下相应的反馈。审核团队可以使用您的帮助来识别质量问题。