重写C++中的规则
Overriding rules in C++
从Java的角度来看,我惊讶地发现您只能重写具有virtual关键字的基方法。在Java中,您使用final关键字来声明一个方法不能被重写。
我脑子里有一个想法,你很少想禁止重写,这样有人就可以按照他们认为合适的方式扩展你的课程。
所以在C++中,如果你觉得有人可能想在某个阶段继承你的类(也许几年后有人认为这是一个很酷的想法),你会让你所有的方法都是虚拟的吗?
还是有一些我不知道的关键原因想要在C++中禁止这种行为?
作为参考,这是我用每种语言做的实验:
Java
public class Base {
void doSomething(){
System.out.println("Doing the base thing");
}
}
public class Derived extends Base {
void doSomething(){
System.out.println("Doing the derived thing");
}
public static void main(String... argv){
Base object = new Derived();
object.doSomething();
}
}
C++
class Base
{
public:
Base(void);
~Base(void);
virtual void doSomething();
};
void Base::doSomething(){
std::cout << "I'm doing the base thingn" << std::endl;
}
class Derived :
public Base
{
public:
Derived(void);
~Derived(void);
void doSomething();
};
void Derived::doSomething(){
std::cout << "I'm doing the dervied thing" << std::endl;
}
int main(void){
Base * object = new Derived;
object->doSomething();
return 0;
}
duffymo和Als正在引导您朝着正确的方向前进。我只是想评论一下你说的一件事:
所以在C++中,如果你觉得有人可能想在某个阶段继承从你的课堂上(也许几年后有人认为这是一个很酷的想法)做你把所有的方法都虚拟化了?
从软件工程的角度来看:如果您没有立即使用继承,并且没有使用接口,那么我不建议将您的方法声明为虚拟方法。
虚拟方法会带来非常轻微的性能下降。对于非关键代码路径,性能影响可能可以忽略不计。但是对于经常被调用的类方法,它可能会累加起来。编译器不能做那么多的内联和直接链接。相反,必须在运行时在v-table数组中查找要调用的虚拟方法。
当我的编码团队中有人在设计对话中说"以后某个时候可能会有人想要……"时,我的"防未来"反模式警报就会响起。设计可扩展性是一回事,但"面向未来的功能"应该推迟到那时。
此外,几年后,那个认为这是一个很酷的想法的人——让他自己将类方法转换为虚拟方法。无论如何,到那时你会从事更大的项目。:)
是的,在C++中,如果在基类中标记为virtual
,则类方法只能是overidden
。
如果您的类是为继承而创建的,并且您的类方法旨在为Base和派生提供不同的行为,则将该方法标记为virtual
。
阅读良好:
何时将C++中的函数标记为虚拟函数
是的,您必须使所有方法都是虚拟的。
Java的立场是,默认情况下,一切都是公平的,禁止它需要采取行动。C++和C#则持相反的观点。
即使没有virtual
,也可以覆盖基类中的方法。
以这个小程序为例:
#include <iostream>
struct A
{
void m()
{ std::cout << "An"; }
virtual void n()
{ std::cout << "An"; }
};
struct B : public A
{
void m()
{ std::cout << "Bn"; }
virtual void n()
{ std::cout << "Bn"; }
};
int main()
{
A a;
a.m();
a.n();
B b;
b.m();
b.n();
A &c = b;
c.m();
c.n();
}
程序的输出为:
A.A.BBA.B
正如您所看到的,方法B::m
覆盖了A
中的相同方法。但只有当使用B
的精确实例时,这才有效。在第三种情况下,当使用对基类的引用时,需要virtual
才能使其工作。
来自以虚拟函数为默认值的语言的程序员往往会惊讶于C++对默认值的选择相反,即非虚拟函数是默认值。然而,请注意,[具体]虚拟功能的合同更难记录和测试,因为实际上涉及两个不同的合同:
- 所有覆盖功能的契约,即功能在概念上的作用
- 具体功能的契约
只记录其中一个并不能真正减少成本,因为另一半根本不清楚。这也意味着,您无法从特定的实现中查看实际的合同是什么(假设您处于文档由源提供的不那么典型的情况)。
- 此代码是否违反一个定义规则
- 生成文件不对文件使用隐式规则
- 变量可能尚未初始化[MIRA 2012规则9.1,强制性]
- 静态结构和一个定义规则
- 尽管遵循了规则,内存泄漏在哪里
- 这是关于成员访问规则的正确摘要吗
- uint_not_usable_without_attribute在业力规则中使用数字生成器时静态断言失败
- 增强精神解析器规则以检测语句中的特殊结尾
- 制作文件:没有规则来制定目标:如何设置正确的规则?
- 为什么此指针值不能转换为整数的规则是什么?
- 传递通用函数,用于梯形规则的数值积分
- C++内存模型中的确切规则阻止在获取操作之前重新排序
- 模板如何影响C++中隐式声明的规则?
- antlr 规则上下文是否可以独立于目标
- Bison/flex 在识别规则后等待输入
- 生成文件中隐式规则中的 -c 标志出错
- 单链接列表实现,规则为 3
- 指针算术规则中的"possibly-hypothetical"是什么意思?
- 假设声明中某些上下文中需要的名称查找规则是什么
- C++ 用于检查容器类中是否存在函数和隐式推导规则的概念