c++ 重载运算符、赋值、深复制和加法
我目前正在对运算符重载进行一些探索,同时重新阅读一些旧的大学教科书,我认为我误解了一些东西,所以希望这对于一些回答者来说是一些很好的简单声誉。 如果这是重复的,请指出我正确的方向。
我创建了一个简单的计数器类,它(在这个阶段)有一个成员 val (一个 int)。
我已经初始化了其中的三个计数器,varOne 到 varThree,并希望第三个计数器是前两个计数器的总和(例如,在下面的代码中 varThree.val 设置为 5)
counter::counter(int initialVal)
{
val = initialVal;
//pVal = new int;
//*pVal = 10; // an arbitrary number for now
}
int main (int argc, char const* argv[])
{
counter varOne(3), varTwo(2), varThree;
varThree = varOne + varTwo;
return 0;
}
重载了operator+,如下所示:
counter operator+(counter& lhs, counter& rhs)
{
counter temp(lhs.val + rhs.val);
return temp;
}
我已经 使其成为非成员函数和计数器类的友元,以便它可以访问私有值。
当添加另一个私有成员 pVal (指向 int 的指针)时,我的问题就开始了。 添加这意味着我不能再执行简单的 varThree = varOne
复制,因为当 varOne 被销毁时,varThree.pVal 仍将指向同一位内存。
我已重载 operator=
如下。
int counter::getN()
{
return *newVal;
}
counter& counter::operator=(counter &rhs)
{
if (this == &rhs) return *this;
val = rhs.val;
delete pVal;
pVal = new int;
*pVal = rhs.getN();
return *this;
}
现在,如果我执行类似 varThree = varOne
的操作,所有内容都会正确复制,但是尝试执行 varThree = varOne + varTwo
会出现以下错误:
counter.cpp: In function ‘int main(int, const char**)’:
counter.cpp:96: error: no match for ‘operator=’ in ‘varThree = operator+(counter&, counter&)(((counter&)(& varTwo)))’
counter.cpp:55: note: candidates are: counter& counter::operator=(counter&)
make: *** [counter] Error 1
看起来好像 counter ::operator=
无法处理 operator+
的返回输出,并且我需要进一步重载 operator=
以接受 Operator+
正在返回,但我运气不佳,我开始认为也许我做了一些根本性错误的事情。
I'm doing some exploration of operator-overloading at the moment whilst re-reading some of my old University text-books and I think I'm mis-understanding something, so hopefully this will be some nice easy reputation for some answerers. If this is a duplicate please point me in the right direction.
I've created a simple counter class that has (at this stage) a single member, val (an int).
I have initialised three of these counters, varOne to varThree, and want the third counter to be the sum of the first two (e.g. varThree.val is set to 5 in the below code)
counter::counter(int initialVal)
{
val = initialVal;
//pVal = new int;
//*pVal = 10; // an arbitrary number for now
}
int main (int argc, char const* argv[])
{
counter varOne(3), varTwo(2), varThree;
varThree = varOne + varTwo;
return 0;
}
I've overloaded operator+ like so:
counter operator+(counter& lhs, counter& rhs)
{
counter temp(lhs.val + rhs.val);
return temp;
}
I've made this a non-member function, and a friend of the counter class so that it can access the private values.
My problem starts when adding another private member, pVal (a pointer to an int). Adding this means that I can no longer do a simple varThree = varOne
copy because when varOne is destroyed, varThree.pVal will still be pointing to the same bit of memory.
I've overloaded operator=
as follows.
int counter::getN()
{
return *newVal;
}
counter& counter::operator=(counter &rhs)
{
if (this == &rhs) return *this;
val = rhs.val;
delete pVal;
pVal = new int;
*pVal = rhs.getN();
return *this;
}
Now if I do something like varThree = varOne
everything copies correctly, however trying to do varThree = varOne + varTwo
gives me the following error:
counter.cpp: In function ‘int main(int, const char**)’:
counter.cpp:96: error: no match for ‘operator=’ in ‘varThree = operator+(counter&, counter&)(((counter&)(& varTwo)))’
counter.cpp:55: note: candidates are: counter& counter::operator=(counter&)
make: *** [counter] Error 1
It looks as though counter::operator=
is having trouble coping with the return output from operator+
, and that I need to overload operator=
further to accept the type that operator+
is returning, but I've had no luck and I'm beginning to think that maybe I've done something fundamentally wrong.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您需要将参数作为 const 引用传递。 例如:
运算符+() 也类似。 为了能够将临时值绑定到函数参数,这是必要的。 当您按值返回时,会创建临时值,因此当您说:
创建一个无名临时值时。 这是正确的做法,但您必须确保诸如赋值操作之类的函数可以通过将其参数设置为 const 来接受此类值。
您还需要为您的类实现复制构造函数和析构函数,尽管缺少这些不会导致编译错误(不幸的是)。
You need to pass your parameters as const reference. For example:
And similarly for operator+(). This is necessary in order to be able to bind temporary values to the function parameter(s). Temporary values are created when you return by value, so when you say:
a nameless temporary is created. This is the right thing to do, but you have to make sure that functions such as the assignment op can accept such values by making their parameters const.
You also need to implement the copy constructor and destructor for your class, though lack of these will not cause compilation errors (unfortunately).
这里的关键(正如之前的海报所提到的)但值得强调的是,C++ 中的表达式可以分为右值或左值。
这些类别背后有很多细节,但是指导您的直觉的一个有用的启发式是:如果您可以获取表达式(例如变量)的地址,那么它就是一个左值(这里的故事还有更多内容,但这是一个好的起点)。
如果它确实不是左值,那么它就是右值 - 右值的一个有用启发是它们代表编译器实例化以使代码正常工作的“隐藏”临时对象。 这些对象是由编译器在幕后创建和销毁的。
为什么这与此相关?
好吧,在 C++98/03 中(我猜你正在使用它),请记住以下两条规则:
1)只有左值表达式可以绑定到非常量引用(忽略强制转换)
2) 右值表达式只能绑定到 const 引用(忽略强制转换)
这里有一个示例会有所帮助:
当您将右值绑定到 const 引用时,您基本上将临时对象的生命周期延长到生命周期(在本例中为作用域)引用的引用(编译器不能只是在该表达式的末尾销毁它) - 因此您最终会得到对有效对象的引用。
我希望这有助于理解为什么您必须将赋值运算符声明为接受 const 引用而不仅仅是非 const 引用,正如其他海报正确推荐的那样。
ps 您的代码还有一些其他问题(例如为什么您要销毁和创建对象在每次赋值时专门指向的内存,以及缺少复制构造函数和析构函数),并且如果没有人通过当这篇文章出现时,我会:)
ps 可能还值得知道的是,C++0x 添加了称为右值引用(非常量)的东西,它优先绑定到右值并为程序员提供极其强大的优化机会(无需依赖编译器的优化能力) - 它们还有助于解决在 C++ 中创建完美转发函数的问题 - 但现在我们离题了;)
The key here (as touched upon by a previous poster) but worth emphasizing is that expressions in C++ can be categorized as being either rvalues or lvalues.
Their is much detail behind those categories, but a useful heuristic to guide your intuition is: if you can take the address of an expression (such as a variable) it is an lvalue (there is much more to the story here, but this is a good place to start).
If it is truly not an lvalue, it is an rvalue - and a useful heuristic for rvalues is that they represent "hidden" temporary objects that the compiler instantiates to make your code work. These objects are created and destroyed by the compiler behind the scenes.
Why is this relevant here?
Well, in C++98/03 (which is what i presume you are using), remember the following two rules:
1) Only lvalue expressions can bind to non-const references (ignoring casts)
2) rvalue expressions can bind to only const references (ignoring casts)
An example will help here:
When you bind an rvalue to a const reference, you basically extend the temporary object's life-time to the life-time (in this case scope) of the reference (and the compiler can not just destroy it at the end of that expression) - so you end up with a reference to a valid object.
I hope this helps in understanding why you have to declare your assignment operator as accepting a const reference and not just a non-const reference, as one of the other posters rightly recommended.
p.s. There are some other issues with your code (such as why you are destroying and creating the memory that your object exclusively points to upon each assignment, and the lack of a copy constructor and destructor), and if no one has addressed them by the time this post appears, i will :)
p.s. It may also be worth knowing that C++0x adds something known as rvalue references (non-const) that preferentially bind to rvalues and provide for extremely powerful optimization opportunities for the programmer (without having to rely on the optimization capabilities of the compiler) - they also help solve the problem of creating the perfect forwarding function in C++ - but now we're digressing ;)
解决此问题的另一种方法是使用 PImpl 模式并交换赋值运算符。 假设您仍然有一个 counter(int) 构造函数,您可以如下编写 operator= 这样做的
好处是,可以将混乱的内存管理函数保留在构造函数和析构函数中应在的位置。
Another way to approach this problem is to use the PImpl pattern and swap for the assignment operator. Assuming that you still have a counter(int) constructor you could write operator= as follows
This has the benefit of leaving the messy memory management functions in the constructor and destructor where they should be.