39

有没有人知道 C++ 中的语言特性或技术来防止子类在父类中覆盖特定方法?

class Base {
public:
    bool someGuaranteedResult() { return true; }
};

class Child : public Base {
public:
    bool someGuaranteedResult() { return false; /* Haha I broke things! */ }
};

即使它不是虚拟的,这仍然是允许的(至少在我使用的 Metrowerks 编译器中),你得到的只是一个关于隐藏非虚拟继承函数 X 的编译时警告。

4

14 回答 14

44

当您可以将final说明符用于虚拟方法(由 C++11 引入)时,您就可以做到。让我引用我最喜欢的文档网站

在虚函数声明中使用时,final 指定该函数不能被派生类覆盖。

适应你的例子,就像:

class Base {
public:
    virtual bool someGuaranteedResult() final { return true; }
};

class Child : public Base {
public:
    bool someGuaranteedResult() { return false; /* Haha I broke things! */ }
};

编译时:

$ g++ test.cc -std=c++11
test.cc:8:10: error: virtual function ‘virtual bool Child::someGuaranteedResult()’
test.cc:3:18: error: overriding final function ‘virtual bool Base::someGuaranteedResult()’

当您使用 Microsoft 编译器时,还请查看sealed关键字。

于 2013-06-03T21:26:36.250 回答
15

几个想法:

  1. 将您的功能设为私有。
  2. 不要让你的函数是虚拟的。不过,这实际上并不能阻止该函数被另一个定义所掩盖。

除此之外,我不知道有一种语言特性会以这样的方式锁定你的函数,从而防止它被重载并且仍然能够通过对子类的指针/引用来调用。

祝你好运!

于 2008-08-20T06:53:40.533 回答
8

听起来您正在寻找的是 Java 语言final关键字的等效项,它可以防止方法被子类覆盖

正如这里的其他人所建议的那样,您真的无法阻止这种情况。此外,这似乎是一个相当常见的问题

于 2008-08-20T07:45:10.393 回答
3

(a) 我不认为将函数设为私有是解决方案,因为这只会对派生类隐藏基类函数。派生类总是可以定义一个具有相同签名的新函数。(b) 使函数非虚拟也不是一个完整的解决方案,因为如果派生类重新定义相同的函数,则始终可以通过编译时绑定调用派生类函数,即 obj.someFunction() 其中 obj 是派生类。

我认为没有办法做到这一点。另外,我想知道您决定禁止派生类覆盖基类函数的原因。

于 2008-09-23T12:02:39.933 回答
2

关于隐藏非虚拟继承函数 X 的编译时警告。

更改编译器设置以使其成为错误而不是警告。

于 2008-08-20T06:55:12.573 回答
2

我猜编译器警告你的是隐藏!它实际上被覆盖了吗?

编译器可能会给你一个警告,但是在运行时,如果指针是父类类型,则将调用父类方法,而不管它指向的对象的实际类型。

这很有趣。尝试为您的编译器制作一个小的独立测试程序。

于 2008-09-23T13:13:01.747 回答
1

为了澄清,你们中的大多数人误解了他的问题。他不是在问“覆盖”一种方法,而是在问是否有办法防止“隐藏”。简单的答案是“没有!”。

这是他的例子

父类定义了一个函数:

int foo() { return 1; }

继承父类的子类再次定义了相同的函数(不覆盖):

int foo() { return 2; }

您可以在所有编程语言上执行此操作。没有什么可以阻止此代码编译(编译器上的设置除外)。您将得到的最好的结果是警告您正在隐藏父母的方法。如果您调用子类并调用 foo 方法,您将得到 2。您实际上已经破坏了代码。

这就是他要问的。

于 2009-10-13T18:09:02.203 回答
0

如果您将子类作为其父类的一种类型,则非虚函数将调用父类的版本。

IE:

Parent* obj = new Child();
于 2008-08-20T06:53:36.647 回答
0

除非您将方法设为虚拟,否则子类无法覆盖它。如果您想阻止子类调用它,请将其设为私有。

所以默认情况下,C++ 会做你想做的事。

于 2008-08-20T06:57:47.247 回答
0

试图阻止某人在子类中使用与您的函数相同的名称与试图阻止某人使用与您在链接库中声明的相同的全局函数名称没有太大区别。

您只能希望那些打算使用您的代码而不是其他人的用户会小心他们如何引用您的代码,并希望他们使用正确的指针类型或使用完全限定的范围。

于 2008-08-21T01:27:11.807 回答
0

在您的示例中,没有函数被覆盖。相反,它是隐藏的(这是一种退化的重载情况)。错误在子类代码中。正如 csmba 所建议的,您所能做的就是更改编译器设置(如果可能);只要您不使用隐藏自己功能的第三方库,就应该没问题。

于 2008-09-23T13:00:30.810 回答
0

从技术上讲,您可以防止虚拟功能被覆盖。但是您将永远无法更改或添加更多内容。那是不由得饱了。正如 faq lite 建议的那样,最好在函数前使用注释。

于 2009-12-11T21:51:56.223 回答
-1

我正在寻找相同的东西,昨天遇到了这个[相当老的]问题。

今天我发现了一个简洁的 c++11 关键字:final. 我认为它可能对下一个读者有用。

http://en.cppreference.com/w/cpp/language/final

于 2016-08-04T06:00:41.170 回答
-2

默认情况下,C++ 方法是私有的且不可覆盖。

  • 您不能覆盖私有方法
  • 您不能覆盖非virtual方法

您可能是指超载吗?

于 2008-08-20T06:54:28.097 回答