从Java的角度来看,我很惊讶地发现你只能覆盖拥有virtual关键字的基本方法。 在Java中,您使用final关键字来声明无法覆盖方法。
我的想法是,我很少想要禁止覆盖,以便有人可以按照他们认为合适的方式扩展课程。
所以在C ++中,如果你觉得有人可能想在某个阶段继承你的课程(也许多年后有人认为这是一个很酷的主意),你是否将所有方法都虚拟化了?
或者是否有一些关键的原因想要在C ++中禁止这个我不知道的?
for Reference这是我用各种语言进行的实验:
爪哇
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 thing\n" << 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;
}
答案 0 :(得分:1)
是的,在C ++中,如果在Base类中标记为overidden
,则类方法只能为virtual
。
如果您的类是为了继承而您的类方法是为Base提供不同的行为并派生,那么将该方法标记为virtual
。
好读:
答案 1 :(得分:1)
是的,您必须将所有方法都设为虚拟。
Java采取的立场是,默认情况下,所有内容都是公平的游戏,禁止它需要采取行动。 C ++和C#采取相反的观点。
答案 2 :(得分:1)
duffymo和Als正朝着正确的方向前进。我只是想对你说的一件事发表评论:
所以在C ++中如果你觉得有人可能想要在某个阶段继承 从你的班级(也许多年后有人认为这是一个很酷的主意)做 你把所有方法都虚拟了吗?
从软件工程的角度来看:如果您没有立即使用继承并且没有使用接口,那么我不建议将您的方法声明为虚拟。
虚拟方法伴随着轻微的性能下降。对于非关键代码路径,性能影响可能微不足道。但是对于被大量调用的类方法,它可以加起来。编译器无法进行内联和直接链接。相反,必须在运行时在v表数组中查找要调用的虚方法。
当我的编码团队中的某个人开始与“有人可能会在某个时候想要......”的设计对话时,那时我的“未来校对”反模式警报响起。设计可扩展性是一回事,但“未来的特征”应该推迟到那时为止。
除此之外 - 这个家伙多年后认为这是一个很酷的主意 - 让他成为拥有将课程方法变为虚拟的人。无论如何,你将在那时进入更大的项目。 :)
答案 3 :(得分:0)
即使没有virtual
,您也可以覆盖基类中的方法。
以这个小程序为例:
#include <iostream>
struct A
{
void m()
{ std::cout << "A\n"; }
virtual void n()
{ std::cout << "A\n"; }
};
struct B : public A
{
void m()
{ std::cout << "B\n"; }
virtual void n()
{ std::cout << "B\n"; }
};
int main()
{
A a;
a.m();
a.n();
B b;
b.m();
b.n();
A &c = b;
c.m();
c.n();
}
该计划的输出是:
A A B B A B
如您所见,方法B::m
会覆盖A
中的相同方法。但这仅在使用B
的确切实例时才有效。在第三种情况下,当使用对基类的引用时,您需要virtual
才能使其工作。