Java C++;

Java C++;,java,c++,overriding,Java,C++,Overriding,从Java的角度来看,我惊讶地发现,您只能重写具有virtual关键字的基本方法。 在Java中,使用final关键字来声明方法不能被重写 我脑子里有个想法,你很少想禁止重写,这样别人就可以根据自己的意愿扩展你的类 在C++中,如果你觉得某人可能希望在某个阶段继承你的类(也许几年后有人认为它是一个很酷的想法)你会让你的方法都是虚拟的吗? 是的,在C++中,类方法只能是“代码>过ID,如果在基类中被标记为代码>虚拟< /代码>。 如果您的类是为继承而创建的,并且您的类方法旨在为Base和deriv

从Java的角度来看,我惊讶地发现,您只能重写具有virtual关键字的基本方法。 在Java中,使用final关键字来声明方法不能被重写

我脑子里有个想法,你很少想禁止重写,这样别人就可以根据自己的意愿扩展你的类

在C++中,如果你觉得某人可能希望在某个阶段继承你的类(也许几年后有人认为它是一个很酷的想法)你会让你的方法都是虚拟的吗? <是否有一些重要的原因,在C++中我想禁止这一点? 作为参考,这是我在每种语言中进行的实验:

爪哇

C++

类基
{
公众:
基(空);
~Base(void);
虚空剂量仪();
};
void Base::doSomething(){

STD::CUT< P>是的,在C++中,类方法只能是“代码>过ID<代码>,如果在基类中被标记为代码>虚拟< /代码>。 如果您的类是为继承而创建的,并且您的类方法旨在为Base和derived提供不同的行为,那么请将该方法标记为
virtual

好书:


是的,您必须将所有方法都虚拟化


java认为默认情况下一切都是公平的,要重写,禁止它需要动作。C++和C语言的观点相反。 可以在基类中重写一个方法,即使没有<代码>虚拟< /C> > < /P> 以这个小程序为例:

#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
{
void m()

{std::coutduffymo和Als正在引导你朝着正确的方向前进。我只想评论一下你说的一件事:

在C++中,如果你觉得某人可能希望在某个阶段继承 从你的班级(也许几年后有人认为这是一个很酷的主意)做什么 你把所有的方法都虚拟化了

从软件工程的角度来看:如果您没有立即使用继承,并且没有使用接口,那么我不建议将您的方法声明为虚拟的

虚拟方法带来的性能下降非常轻微。对于非关键代码路径,性能影响可能可以忽略不计。但对于被多次调用的类方法,它可以累加起来。编译器不能进行太多的内联和直接链接。相反,要调用的虚拟方法必须在ru的v-table数组中查找有时

当我的编码团队中的某个人开始与“某个人以后可能需要…”进行设计对话时,我的“防未来”反模式警报就会响起。设计可扩展性是一回事,但“面向未来的功能”应该推迟到那时


此外,那些认为这是一个很酷的想法的人——让他自己来把类方法转换成虚拟的。那么,你将在更大的项目上进行反正。))< P > > P >来自虚拟函数默认的语言的程序员往往会惊讶于C++有逆向选择的默认值,即非虚拟性。l是默认值。但是,请注意,[具体]虚拟函数的契约很难记录和测试,因为实际上涉及两个不同的契约:

  • 所有覆盖函数的约定,即函数在概念上的作用
  • 具体功能发生作用的契约

  • 只记录其中的一个并不能真正解决问题,因为另一半根本不清楚。这也意味着您无法从具体的实现中看出实际的合同是什么(假设您处于由源代码提供文档的非典型情况下).

    可能重复的
    virtual
    关键字对于
    越界
    是必需的,或者您得到的是
    函数隐藏
    。派生结构
    B
    中的方法
    m()
    隐藏基本结构
    A
    方法,而方法
    n()
    B中的
    重写了基结构方法。在B中对m()所做的操作称为重载(这也会导致基类版本被隐藏)在C++中,函数必须显式声明为虚拟的,使其可以重写。注意,虚方法的性能命中仅针对C++,或者如果实际有不同的重写方法(甚至可以在优化中内联,等等)。举一个例子来说明为什么让所有东西都虚拟化或一般地继承可能不是一个好主意。实际上,经常看看那些从Java中的
    HashMap
    继承的人,他们的结果并不像他们想象的那样。
        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;
    
        }
    
    #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