我正在学习运营商重叠。我创建了一个简单的类来测试它。
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;
};
我试图找出,如何用重载的操作数来中断字符串。我宣布了我的功能
Beer operator + (string a)const {
this -> name = this -> name +" "+a;
};
引发传递const字符串的错误。
我尝试使用
Beer operator + ( const string *a)const {
swap(this -> name , this -> name + " " + a);
return *this;
};
其中抱怨一个是cosnst字符串,而secon一个是基本字符串。
这个想法很简单。
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>)'|
// erro with string
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]|
答案 0 :(得分:2)
评论:
不要包含整个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; }
通过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
在+
运算符中取一个字符串,您应该返回一个新对象,而不是修改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;
}
即使您的课程旨在试验操作员,您也应该始终考虑操作员是否让生活更轻松。例如,您的班级有三名成员。除非从类的语义中清楚地看出,否则不会立即明白这些成员中的哪一个将被操作。例如,使用名为addToOne
,addToTwo
和appendToName
的方法代替运算符,或者只是让用户通过setter设置成员,会更清楚,比如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()
等
答案 1 :(得分:1)
Beer operator + (string a)const {
this -> name = this -> name +" "+a;
};
你不应该改变调用+运算符的对象的内容,如果你执行A = B + C,则不应该改变B的内容。编译器正确地通知了你,因为它是一个const函数。
而是创建一个临时对象来保存'sum'并返回它。
Beer operator + (string a)const {
return Beer(one, two, name + " " + a);
};
答案 2 :(得分:0)
在operator+()
此处:
Beer operator+( string a ) const
{
this->name = this->name + " " + a;
};
函数签名上的const
是编译器的保证,当调用函数时,您不会更改对象中的数据,但是您更改了对象中的数据。