重载运算符和修改字符串
Overloading operator and modifiyng string
我正在学习运算符重叠。我创建了简单的 class 来测试它。
class Beer{
public:
Beer(int oner , int twor , string name){
this -> one = oner;
this -> two = twor;
this -> name = name;
};
int getOne(){
return this -> one;
};
int getTwo(){
return this -> two;
};
string getName(){
return this -> name;
};
Beer operator + (const Beer &a)const {
return Beer(5,two+a.two,"firstName");
};
Beer operator + (string a)const {
this -> name = this -> name +" "+a;
};
private:
int one;
int two;
string name;
};
我想弄清楚,如何使用重载的操作数对字符串进行 midify。我声明的函数
Beer operator + (string a)const {
this -> name = this -> name +" "+a;
};
抛出有关传递常量字符串的错误。
我尝试使用
Beer operator + ( const string *a)const {
swap(this -> name , this -> name + " " + a);
return *this;
};
抱怨一个是 cosnst 字符串,第二个是基本字符串。
这个想法很简单。
Beer one ( 5, 6, "one")
one + "two"
// one.name = "one two"
怎样才是正确的做法?
// 交换错误
error: no matching function for call to 'swap(const string&, std::basic_string<char>)'|
// 字符串错误
passing 'const string {aka const std::basic_string<char>}' as 'this' argument of 'std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(std::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' discards qualifiers [-fpermissive]|
在您的 operator+()
此处:
Beer operator+( string a ) const
{
this->name = this->name + " " + a;
};
函数签名上的const
是对编译器的保证,当函数被调用时,你不会改变对象中的数据,但你改变了对象中的数据。
Beer operator + (string a)const {
this -> name = this -> name +" "+a;
};
你不应该改变被调用的 + 运算符的对象的内容,毕竟如果你执行 A = B + C,B 的内容不应该改变。编译器正确地通知了您这一点,因为它是一个 const 函数。
而是创建一个临时对象来保存 'sum' 和 return 它。
Beer operator + (string a)const {
return Beer(one, two, name + " " + a);
};
评论:
不要包含整个 std
命名空间。您很可能 运行 与您自己的代码发生严重的名称冲突。最多,使用您明确需要的符号,例如using std::string;
.
除非你需要一个值的副本来修改,否则通过 const 引用传递像 std::string
这样的大对象。当您将参数声明为具有值类型 std::string
时,您会收到该字符串的副本,除非您需要副本以在函数内部进行修改,否则这是昂贵的。
这是 C++ 标准长期存在的问题:像这样的实现细节,本应与函数的用户无关,却泄漏到接口(函数的声明)中。尽管如此,当有一份副本有意义时,让编译器给你一份,而不必输入那么多。因此:
// prefer this
std::string fooize(std::string foo) {
assert(foo.size() > 0);
foo.insert(1, "foo");
return foo;
}
// over this
std::string fooize(const std::string & bar) {
assert(bar.size() > 0);
auto foo = bar;
foo.insert(1, "foo");
return foo;
}
使用初始化列表,你就不需要做愚蠢的名字体操(你有 oner
,twor
名字:
Beer(int one, int two, const std::string & name) :
one(one),
two(two),
name(name)
{}
声明只读访问器 const:
int getOne() const { return one; }
Return const 引用的大值,如字符串;用户代码可能会让编译器在需要时自动帮助制作副本:
const std::string & getName() const { return name; }
// use:
Beer beer{0,0,""};
std::cout << (beer.getName() + "!") << std::endl; // makes a copy of name as needed
在接受字符串的 +
运算符中,您应该 return 一个新对象,而不是修改 this
。你几乎应该按照其他操作员的方式去做 + 你已经做到了。
Beer operator +(const std::string & a) const {
return Beer(one, two, name + " " + a);
};
如果你想修改你的对象,你想要operator +=
:
Beer & operator+=(const std::string & a) {
name += " ";
name += a;
return *this;
}
即使您的 class 旨在试验运算符,您也应该始终考虑运算符是否让生活更轻松。例如,您 class 有三个成员。除非从 class 的语义中清楚地看出,否则这些成员中的哪些将被操作并不是很明显。例如,将方法命名为 addToOne
、addToTwo
和 appendToName
会更清晰,而不是运算符,或者只是让用户通过设置器设置成员,喜欢 setOne(int one) { this->one = one; }
。然后用户只需执行 beer.setOne(beer.getOne() + 2);
.
考虑在没有 get
前缀的情况下命名 getter,例如
class Beer {
int m_one;
public int one() const { reeturn m_one; }
};
用户输入更少。标准库以及 boost
和 Qt
等大型库都遵循此约定,例如你有std::string::size()
,没有std::string::getSize()
,等等
我正在学习运算符重叠。我创建了简单的 class 来测试它。
class Beer{
public:
Beer(int oner , int twor , string name){
this -> one = oner;
this -> two = twor;
this -> name = name;
};
int getOne(){
return this -> one;
};
int getTwo(){
return this -> two;
};
string getName(){
return this -> name;
};
Beer operator + (const Beer &a)const {
return Beer(5,two+a.two,"firstName");
};
Beer operator + (string a)const {
this -> name = this -> name +" "+a;
};
private:
int one;
int two;
string name;
};
我想弄清楚,如何使用重载的操作数对字符串进行 midify。我声明的函数
Beer operator + (string a)const {
this -> name = this -> name +" "+a;
};
抛出有关传递常量字符串的错误。
我尝试使用
Beer operator + ( const string *a)const {
swap(this -> name , this -> name + " " + a);
return *this;
};
抱怨一个是 cosnst 字符串,第二个是基本字符串。
这个想法很简单。
Beer one ( 5, 6, "one")
one + "two"
// one.name = "one two"
怎样才是正确的做法?
// 交换错误
error: no matching function for call to 'swap(const string&, std::basic_string<char>)'|
// 字符串错误
passing 'const string {aka const std::basic_string<char>}' as 'this' argument of 'std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(std::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' discards qualifiers [-fpermissive]|
在您的 operator+()
此处:
Beer operator+( string a ) const
{
this->name = this->name + " " + a;
};
函数签名上的const
是对编译器的保证,当函数被调用时,你不会改变对象中的数据,但你改变了对象中的数据。
Beer operator + (string a)const {
this -> name = this -> name +" "+a;
};
你不应该改变被调用的 + 运算符的对象的内容,毕竟如果你执行 A = B + C,B 的内容不应该改变。编译器正确地通知了您这一点,因为它是一个 const 函数。
而是创建一个临时对象来保存 'sum' 和 return 它。
Beer operator + (string a)const {
return Beer(one, two, name + " " + a);
};
评论:
不要包含整个
std
命名空间。您很可能 运行 与您自己的代码发生严重的名称冲突。最多,使用您明确需要的符号,例如using std::string;
.除非你需要一个值的副本来修改,否则通过 const 引用传递像
std::string
这样的大对象。当您将参数声明为具有值类型std::string
时,您会收到该字符串的副本,除非您需要副本以在函数内部进行修改,否则这是昂贵的。这是 C++ 标准长期存在的问题:像这样的实现细节,本应与函数的用户无关,却泄漏到接口(函数的声明)中。尽管如此,当有一份副本有意义时,让编译器给你一份,而不必输入那么多。因此:
// prefer this std::string fooize(std::string foo) { assert(foo.size() > 0); foo.insert(1, "foo"); return foo; } // over this std::string fooize(const std::string & bar) { assert(bar.size() > 0); auto foo = bar; foo.insert(1, "foo"); return foo; }
使用初始化列表,你就不需要做愚蠢的名字体操(你有
oner
,twor
名字:Beer(int one, int two, const std::string & name) : one(one), two(two), name(name) {}
声明只读访问器 const:
int getOne() const { return one; }
Return const 引用的大值,如字符串;用户代码可能会让编译器在需要时自动帮助制作副本:
const std::string & getName() const { return name; } // use: Beer beer{0,0,""}; std::cout << (beer.getName() + "!") << std::endl; // makes a copy of name as needed
在接受字符串的
+
运算符中,您应该 return 一个新对象,而不是修改this
。你几乎应该按照其他操作员的方式去做 + 你已经做到了。Beer operator +(const std::string & a) const { return Beer(one, two, name + " " + a); };
如果你想修改你的对象,你想要
operator +=
:Beer & operator+=(const std::string & a) { name += " "; name += a; return *this; }
即使您的 class 旨在试验运算符,您也应该始终考虑运算符是否让生活更轻松。例如,您 class 有三个成员。除非从 class 的语义中清楚地看出,否则这些成员中的哪些将被操作并不是很明显。例如,将方法命名为
addToOne
、addToTwo
和appendToName
会更清晰,而不是运算符,或者只是让用户通过设置器设置成员,喜欢setOne(int one) { this->one = one; }
。然后用户只需执行beer.setOne(beer.getOne() + 2);
.考虑在没有
get
前缀的情况下命名 getter,例如class Beer { int m_one; public int one() const { reeturn m_one; } };
用户输入更少。标准库以及
boost
和Qt
等大型库都遵循此约定,例如你有std::string::size()
,没有std::string::getSize()
,等等