C++ - 方法覆盖未按预期表达
C++ - Method Override Isn't Expressed as Expected
我有一个 Base class Point
(表示 space 中的一个 2D 点),它对于移动操作是非线程安全的;所以我定义了一个继承的 class LockedPoint
来覆盖基础 class 中的 2 个方法: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> )
为了直观地看到 "unlocked" 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
是 "corrupted",正如预期的那样(到最后它应该等于 (0,0)
,但事实并非如此)。但是,如果我将 p
更改为 LockedPoint
,仍会调用 moveBy
的基本版本(通过打印调试验证)。
我阅读了方法 "overriding"(显然更正确地称为 "method hiding"),据我所知,如果重写方法与基方法具有相同的签名,它会隐藏基版本,并改为调用。尽管 2 具有相同的签名,但为什么要调用基本方法?我唯一能想到的是因为我在 messWithPoint
的参数列表中指定了 Point
,它按字面意思调用 Point
的版本。如果我将签名更改为 void messWithPoint(LockedPoint& p, int type)
,结果 LockedPoint
就是预期的 (0,0)
。是不是应该"see"传递的LockedPoint
覆盖used方法,使用"least hidden"版本?
如果这不是它的工作方式,是否有一种方法可以指定采用基础 class,但让它使用任何可用的覆盖版本?
成员函数不是虚函数,所以使用编译时已知的class中的函数。
然而,对于像点这样的简单class,使用虚拟成员函数或提供自动互斥有悖于C++不为不用而付费的理念。
复制积分即可。
我有一个 Base class Point
(表示 space 中的一个 2D 点),它对于移动操作是非线程安全的;所以我定义了一个继承的 class LockedPoint
来覆盖基础 class 中的 2 个方法: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> )
为了直观地看到 "unlocked" 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
是 "corrupted",正如预期的那样(到最后它应该等于 (0,0)
,但事实并非如此)。但是,如果我将 p
更改为 LockedPoint
,仍会调用 moveBy
的基本版本(通过打印调试验证)。
我阅读了方法 "overriding"(显然更正确地称为 "method hiding"),据我所知,如果重写方法与基方法具有相同的签名,它会隐藏基版本,并改为调用。尽管 2 具有相同的签名,但为什么要调用基本方法?我唯一能想到的是因为我在 messWithPoint
的参数列表中指定了 Point
,它按字面意思调用 Point
的版本。如果我将签名更改为 void messWithPoint(LockedPoint& p, int type)
,结果 LockedPoint
就是预期的 (0,0)
。是不是应该"see"传递的LockedPoint
覆盖used方法,使用"least hidden"版本?
如果这不是它的工作方式,是否有一种方法可以指定采用基础 class,但让它使用任何可用的覆盖版本?
成员函数不是虚函数,所以使用编译时已知的class中的函数。
然而,对于像点这样的简单class,使用虚拟成员函数或提供自动互斥有悖于C++不为不用而付费的理念。
复制积分即可。