我有一个基类Point
(表示空间中的2D点),它对于移动操作是非线程安全的;所以我定义了一个继承的类LockedPoint
,它覆盖了基类中的两个方法:moveTo
和moveBy
:
void Point::moveTo(float xPos, float yPos) {
x = xPos;
y = yPos;
}
void Point::moveBy(float xOff, float yOff) {
x += xOff;
y += yOff;
}
void LockedPoint::moveTo(float xPos, float yPos) {
MutGuard m(lock);
x = xPos;
y = yPos;
}
void LockedPoint::moveBy(float xOff, float yOff) {
MutGuard m(lock);
x += xOff;
y += yOff;
}
( where x and y = private member variables,
lock = a private mutex, and
MutGuard = typedef lock_guard<mutex> )
通过&#34;解锁&#34;直观地看到问题。 Point
,我写了一个测试程序:
void sleepForMS(long ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}
void messWithPoint(Point& p, int type) {
float n = 1;
if (type) n *= -1;
for (long i = 0; i < 10000; i++) {
p.moveBy(n, n);
sleepForMS(rand() % (type ? 2 : 3));
if (i % 500 == 0)
std::cout << i << ":\t" << p << std::endl;
}
}
int main(int argc, char* argv[]) {
using namespace std;
Point p;
thread t1(messWithPoint, std::ref(p), 0);
sleepForMS(33);
thread t2(messWithPoint, std::ref(p), 1);
cout << "Started\n";
t1.join();
t2.join();
cout << p << endl;
}
使用Point
时,生成的p
已被&#34;损坏&#34;,正如预期的那样(它应该等于(0,0)
到最后,并且它不会)。如果我将p
更改为LockedPoint
,则仍会调用moveBy
的基本版本(通过打印调试进行验证)。
我读了方法&#34;覆盖&#34; (显然更正确地称为&#34;方法隐藏&#34;),根据我的理解,如果重写方法与基本方法具有相同的签名,它会隐藏基本版本,而是被调用。为什么然后调用基本方法,尽管2具有相同的签名?我唯一能想到的是因为我在Point
的参数列表中指定了messWithPoint
,它按照字面意思并调用Point
& #39; s版本。如果我将签名更改为void messWithPoint(LockedPoint& p, int type)
,则生成的LockedPoint
为(0,0)
,符合预期。不应该&#34;看&#34;传递的LockedPoint
会覆盖使用过的方法,并使用&#34;最少隐藏的&#34;版本
如果它不是如何工作的,有没有办法指定基类,但让它使用任何可用的重写版本?
答案 0 :(得分:2)
成员函数不是虚函数,因此使用编译时已知类中的函数。
然而,对于一个简单的类,例如点,使用虚拟成员函数或提供自动互斥违背了C ++的想法,即不支付你不使用的内容。
只需复制点。