Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java final methods vs c++ nonvirtual functions

are java final methods and c++ nonvirtual methods different or the same? How?

like image 249
Glove Avatar asked Apr 18 '11 04:04

Glove


3 Answers

They are different.

  • C++ non-virtual methods are not dispatched, and do not override anything.

  • Java final methods are dispatched, and can override methods in their classes superclasses.

However, they are the similar in the respect that neither C++ non-virtual methods or Java final methods can be overridden. They are also similar in the sense that if you have some object whose static type is the type in question, the runtime system does not need to dispatch the method call.

To illustrate the difference, consider these two Java classes:

public class A {
    public String toString() {
        return "A";
    }
}

public class B extends A {
    public final String toString() {
        return "B";
    }
}

A a = ...
B b = ...
a.toString();  // could call A.toString() or B.toString() - dispatch
b.toString();  // could only call B.toString() - no dispatch required
               // but it will behave the same as if dispatching had occurred.

In the C++ equivalent where B::toString() was non-virtual, I believe a.toString() could not dispatch to B::toString(). (I'm a bit rusty on my C++ ... )


(In fact, the Java JIT compiler is capable of detecting cases where virtual dispatching is not needed ... without you declaring classes or methods as final. Thus, the true purpose of final is to specify that a method shall not be overridden or a class shall not be extended ... and have the Java compiler check this for you.)

like image 173
Stephen C Avatar answered Oct 21 '22 05:10

Stephen C


You can still declare non-virtual member functions with the same signature in inheriting classes in C++, where-as Java explicitly forbids declaring methods with the same signature in which the base class declares that method final. Virtuality in C++ just helps find the correct function to call when dealing with inheritance/polymorphism.

Example:

#include <iostream>

class Base
{
public:
    void doIt()
    {
        std::cout << "from Base.doIt()" << std::endl;
    }
};

class Child : public Base
{
public:

    void doIt()
    {
        std::cout << "from Child.doIt()" << std::endl;
    }
};

int main()
{
    Base a;
    a.doIt(); // calls Base.doIt()
    Child b;
    b.doIt(); // calls Child.doIt()
    Base *c = new Base();
    c->doIt(); // calls Base.doIt()
    Child *d = new Child();
    d->doIt(); // calls Child.doIt()
    Base *e = new Child();
    e->doIt(); // calls Base.doIt()
    std::cin.ignore();
    return 0;
}

The comparable example in Java using final will result in a compiler error:

public class Base
{
    public final void doIt()
    {
        System.out.println("In Base.doIt()");
    }
}

public class Child extends Base
{
    public void doIt() // compiler error: Cannot overload the final method from Base
    {
        System.out.println("In Child.doIt()");
    }
}

For more explanation on Polymorphism in C++, see cplusplus.com: Polymorphism

Effictively, though, both methods have similar goals: to prevent overriding of a function in the base class. They just go about it in slightly different ways.

like image 39
helloworld922 Avatar answered Oct 21 '22 05:10

helloworld922


They are very different, in fact, I would say, completely unrelated.

In C++, if a base class has a non-virtual member function, then, you can declare, in a derived class, a non-virtual member function with the same name. The effect will be that the derived class' member function will hide the base class' member function. And no virtual dispatching can occur. As in the following:

struct Base {
  void foo() {
    std::cout << "Base::foo called!" << std::endl;
  };
};

struct Derived : Base {
  void foo() { 
    std::cout << "Derived::foo called!" << std::endl;
  };
};

int main() {
  Derived d;
  d.foo();    //OUTPUT: "Derived::foo called!"
  Base* b = &d;
  b->foo();   //OUTPUT: "Base::foo called!"
};

The above shows how the member function of the derived class hides the base class function. If you have a pointer to a base class, since the functions are non-virtual, the virtual table is not used to resolve the call and thus, the foo function from the base class will be called. The point here is that, in C++, nothing prevents you from creating another function in the Derived class with the same name (note that a different signature will still cause the hiding of all the base class' member functions with the same name). All you will get is a compiler warning telling you that the member function of the Derived class hides member function(s) of the Base class.

A final member function in Java is completely different. In Java, all member functions are virtual. So you can't turn-off the virtual dispatching like you can in C++. A final member function just means that any subsequent derived class will not be allowed (an error will occur) to declare a member function with the same name (and signature). But virtual dispatch (and thus, overriding, in the dynamically polymorphic sense) still occurs between the interface / base class that declared the original member function and the derived class that marked it as final. It is just that later overriding of the function is strictly forbidden (i.e. trying the above code with foo() marked as final in the Base class would give an error in the declaration of the Derived class, because the foo() there would not be allowed).

As you see, the two concepts are completely different.

  • In C++, with a non-virtual member function, virtual dispatching does not occur (thus, no "overriding" in the traditional sense) but you are allowed to have derived classes with member functions of the same name (and it can be useful sometimes in "static polymorphism").
  • In Java, with a final member function, virtual dispatching still occurs, but overriding in subsequent derived classes is strictly forbidden.
like image 2
Mikael Persson Avatar answered Oct 21 '22 06:10

Mikael Persson