4
#include <iostream>
class A{
    public:
        void k(){
            std::cout << "k from A";
        }
};
class B:public A{
    public:
        int k(){
            std::cout << "k from B"; 
            return 0;
        }
};
int main(){
    B obj;
    obj.k();

    return 0;
}

without virtual it's working fine, But When I changed A's function to virtual then It's saying return type should be same why?

I tried same thing in Java:

class X{
    public void k(){
        System.out.println("k From X");
    }
}
public class Y{
    public int k(){
        System.out.println("k From Y");
        return 0;
    }
}

Java also showing error when I tried different return type in sub-class. ( I think because by default all instance methods are virtual by default) I was expecting int k() should hide void k() and int k() should invoke from Y's object.

So I think it's problem with virtual. Why child class should be use same return type when function declared as virtual?

If it polymorphic behavior problem. Then I think object is enough to determined the function calling.

Example:

class X{
    public void k(){
        System.out.println("k From X");
    }
}
public class Y extends X{
    public int k(){
        System.out.println("k From Y");
        return 0;
    }
    public static void main(String[] args){
        X obj=new Y();
        obj.k(); // object Y found now just call k() from Y.
    }
}

Why can't we change return type in sub-class or child class?

double-beep
  • 5,031
  • 17
  • 33
  • 41
Asif Mushtaq
  • 3,658
  • 4
  • 44
  • 80

4 Answers4

4

You guessed correctly, "polymorphic" is the key word :) Polymorphism means that, if Y is a subclass of X, then Y effectively is X, and can be used as X anywhere.

Now, that means, if X has a method void k(), then Y must also have the same method (otherwise, you would not be able to use it as X). But you cannot have two different methods with the same signature, and therefore Y.k() must also return void (otherwise, it would be a different method).

In C++ case, non-virtual functions aren't polymorphic: A.k and B.k are two completely different methods in that case, and therefore there is no restriction.

To put it simply, let's change your example a little bit: suppose, that you defined X.k to return int, and Y.k() as void. Imagine a function like this:

     int plusOne(X x) {
        return x.k() + 1
     }

This should compile and work, right? But what about plusOne(new Y())? This must also work, because Y is X ... but, if it was possible for Y.k() to return a void, what would plusOne do with it?

Dima
  • 39,570
  • 6
  • 44
  • 70
  • Just one thing more. I declare parent's method final and after that sub-class also required same return type. why? (final methods are not virtuals) then? – Asif Mushtaq Mar 12 '16 at 15:18
  • No, they are still virtual, they just cannot be overriden. – Dima Mar 12 '16 at 15:27
  • Read comment under dasblinkenlight's Answer. – Asif Mushtaq Mar 12 '16 at 15:28
  • That comment isn't' exactly correct, but it doesn't really matter: whether the parent method is final or not, the subclass must have it. It cannot have two different methods with the same signature, therefore you cannot create another `k` with a different return type. – Dima Mar 12 '16 at 15:29
  • I read final method are not virtual. http://stackoverflow.com/a/12752387/2769917 ( Can you explain or give me any another example why the return type should be same in non-virtual methods too? ) C++ allows to create another method in child-class with different return type. – Asif Mushtaq Mar 12 '16 at 15:32
  • Whether it is "virtual" or not is debatable, and depends on what exactly you mean by "virtual" (and by "it" :)). I suggest that you ignore that issue, and just focus on the question of why `Y` cannot have `k` with a different return type. Whether `int X.k()` is "final" or not, `Y` _must_ have that method too. `void k()` is a _different_ method, and you cannot have two different methods with the same signature in the same class. – Dima Mar 12 '16 at 15:35
  • C++ is allowing it. but java not. :( – Asif Mushtaq Mar 12 '16 at 15:38
  • In C++ if `k` is non-virtual, subclasses effectively _do not_ have that method (only superclass has it), and thus can declare a different one. In this sense, final methods in java are still virtual. _private_ methods in java are truly not virtual. If `X.k` was private, then you could declare a different one in `Y`. – Dima Mar 12 '16 at 15:38
  • Yes I can declare `k` in Y with different return type. Just test yourself and make `X.k` private. and it proved that `private` method not inherit. – Asif Mushtaq Mar 12 '16 at 15:43
  • Yes, that's exactly what I said in the previous comment :) Private methods are not virtual. – Dima Mar 12 '16 at 15:56
3

If it polymorphic behavior problem. Then I think object is enough to determined the function calling

Dynamic polymorphism happens at run time, but the type of the return value is determined at compile time.

why we can't change return type in sub-class or child class?

Think about the following example, (To be convenient for explanation I changed your sample code a little about the return type)

class A{
    public:
        virtual int k(){  // returns int
            std::cout << "k from A";
            return 0;
        }
};
class B:public A{
    public:
        std::string k(){  // returns std::string
            std::cout << "k from B";
            return std::string();
        }
};
int main(){
    A* pa = new B;
    int r = pa->k(); // r is supposed to be int, the type is deduced at compile time

    delete pa;
    return 0;
}

Calling the virtual function f() via base class pointer (or reference), an int is supposed to be returned, but according to the result of dynamic dispatch, B::k() will be called in fact, but it will return a totally different type (i.e. std::string). It's conflicting and ill-formed.

From the c++ standard, $10.3/7 Virtual functions [class.virtual]

The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
2

Virtual functions of C++ are part of the interface of your class, while non-virtual may be part of implementation as well. When you extend a class, you tell the compiler that you are going to comply with all of its interface, including signatures of its virtual functions.

All non-private / non-final Java methods are virtual, so the same argument applies to them.

As far as object type being sufficient to determine what method to call goes, you may not necessarily know the type at compile time. The compiler must determine the way to look up the method by the static type, including a virtual look-up. This requires the compiler to know the signature and the return type.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • *"All non-private Java methods are virtual"* - All non-private non-*final* Java methods are virtual. – Christian Hackl Mar 12 '16 at 14:55
  • `This requires the compiler to know the signature and the return type.` why return type? can you explain please? – Asif Mushtaq Mar 12 '16 at 15:35
  • 1
    @UnKnown The compiler must know the return type because it may need to apply type promotions. For example, if your member-function returns an `int`, and you are assigning the result to a variable of type `float`, the compiler needs to know that it needs to "promote" the type. – Sergey Kalinichenko Mar 12 '16 at 15:44
0

I have no idea why you posted this question again when I already gave you the answer here. But here is the correct answer again.

Java methods and C++ virtual functions can be hidden, but different return types are allowed when overriding, as long as they are compatible. It is only conflicting return types that are disallowed. For example, in C++:

struct Base {
    virtual Base* f() { return nullptr; }
};

struct Derived : Base {
    Derived* f() override { return nullptr; }
};

And in Java:

class Base {
    Base f() { return null; }
}

class Derived extends Base {
    @Override
    Derived f() { return null; }
}
Community
  • 1
  • 1
Joseph Thomson
  • 9,888
  • 1
  • 34
  • 38