提问人:Santilín 提问时间:6/25/2023 最后编辑:Santilín 更新时间:6/25/2023 访问量:101
不能在 std::string 周围创建一个只导致“语法糖”的包装器
Can not create a wrapper around std::string that results in only "syntax sugar"
问:
我知道 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:
这个建议的问题确实解释了为什么我的代码不起作用,但它没有像公认的问题那样提出任何替代方案。
答:
5赞
Jan Schultke
6/25/2023
#1
您的代码的问题在于返回 ,而不是 .类型之间不存在隐式转换,因此无法编译 return 语句。
在继承层次结构中有一个隐式转换,即您可以转换为 ,但不能转换为 。substr
std::string
ExtendedString
ExtendedString
std::string
要仅针对您的函数解决此问题:left
- 您可以隐式构造函数:
ExtendedString(const std::string&)
- 显式构造:
return ExtendedString(substr(...))
但是,一般来说,您尝试执行的操作在 C++ 中是不可能的。您继承的每个成员函数都不会返回,因此您有错误的接口。C++ 无法定义扩展方法,而扩展方法正是您正在模仿的功能。std::string
ExtendedString
“干净”选择
- 创建从 到 的隐式转换,但这会导致不必要的复制
std::string
ExtendedString
- 注意:这是您在声明时所做的
ExtendedString(const std::string &s);
- 注意:这是您在声明时所做的
- 私下继承,或者更好的是,将其包装为成员
std::string
- 为具有的每个成员函数创建包装函数,并在必要时使它们获取/返回
std::string
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)
-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::string
std::string
std::string
1赞
NotTheDr01ds
6/27/2023
欢迎来到 Stack Overflow!您(目前)的 19 个答案中的大部分或全部(以及您的大多数评论回复)似乎可能全部或部分由 AI(例如 ChatGPT)编写,到目前为止,我检查过的太多答案似乎存在错误,这些错误已在评论中指出。请注意,此处禁止发布 AI 生成的内容。如果您使用 AI 工具来协助回答任何问题,我鼓励您将其删除。谢谢!
1赞
NotTheDr01ds
6/27/2023
读者应该仔细和批判性地审查这个答案,因为人工智能生成的信息通常包含根本性的错误和错误信息。如果您发现质量问题和/或有理由相信此答案是由 AI 生成的,请留下相应的反馈。审核团队可以使用您的帮助来识别质量问题。
评论
explicit
return ExtendedString{substr(0, n>size()?size():n)};