0
    #include <iostream>
    using namespace std;

    class x{
      public:
      virtual void print(double a,int x) {cout<<"Class x"<<endl;}
    };

    class y: public x{
     public:
     void print(char a) {cout<<"Class y char: "<<a<<endl;}
    };

    int main()
    {
     y *t = new y();
     t->print(1.0,2); //Does not work, if function name matched in derived class, it will not look in parent, even if the matched function can't be executed.
     return 0;
    }

This code, only looks in the derived class for function "print" and does not go to the parent class for lookup ever, as expected.

But,

    #include <iostream>
    using namespace std;

    class x{
      public:
      virtual void print(double a) {cout<<"Class x double"<<endl;}
      virtual void print(int a) {cout<<"Class x int"<<endl;}
    };

    class y: public x{
     public:
     void print(double a) {cout<<"Class y double"<<endl;}
     void print(char a) {cout<<"Class y char"<<endl;}
    };

    int main()
    {
     x *t = new y();
     t->print(1);//this calls print(int) in base/parent class x
     return 0;
    }

This code looks into the derived class after it does not find exact matching signature and name in derived class, it goes into base class.

I know that the lookup process for a non polymorphic object of derived class is:

  1. Looks into base class for matching function name

    if found ->
    if exectuable -> execute, else -> error

    else -> error

But I want to know the lookup process for the polymorphic objects.

EDIT:

If the second case only looks into the base class then,

3)

    #include <iostream>
    using namespace std;

    class x{
      public:
      virtual void print(double a){cout<<"Class x double"<<endl;}
      virtual void print(int a) {cout<<"Class x int"<<endl;}
    };

    class y: public x{
     public:
     void print(char a) {cout<<"Class y char: "<<a<<endl;}
     void print(double a) {cout<<"Class y double"<<endl;}
    };

    int main()
    {
     x *t = new y();
     t->print('a');//works
     return 0;
    }
    #include <iostream>
    using namespace std;

    class x{
      public:
      virtual void print(double a){cout<<"Class x double"<<endl;}
      //virtual void print(int a) {cout<<"Class x int"<<endl;}
    };

    class y: public x{
     public:
     //void print(char a) {cout<<"Class y char: "<<a<<endl;}
     void print(double a) {cout<<"Class y double"<<endl;}
    };

    int main()
    {
     x *t = new y();
     t->print(1.0);//calls y::print(double)
     return 0;
    }

Why does case 3 work, where derived class y::print(char) is called and case 4 where y::print(double) is called (which is the entire point of polymorphism with virtual functions)?

Robert Page
  • 366
  • 4
  • 10
  • *This code looks into the derived class after it does not find exact matching signature and name in derived class, it goes into base class.* That's not true. It never looks in the derived class since the function call is through a pointer to `x` it only looks in the base class. The fact that a virtual function resolves to the correct derived class is a run-time feature and doesn't have anything to do with overload sets. – super Nov 26 '20 at 10:45
  • @super, no your provided link does not clear my doubts. And I don't think that the compiler in this case starts lookup from base class, as when I run the program without the print(char) in y and print(int) in x, the print(double) of y(child class) is called instead of the parent class – Robert Page Nov 26 '20 at 10:56
  • I want to know the exact lookup process in this case – Robert Page Nov 26 '20 at 10:57
  • 1
    Note polymorphism is not related to your problem. – Marek R Nov 26 '20 at 11:01
  • Your second piece of code uses the base interface, which has `void print(int)` and `void print(double)`. The compiler doesn't look anywhere else. Your first code uses the derived interface, which only has `void print(char)`. – molbdnilo Nov 26 '20 at 11:05
  • @molbdnilo, but print('a') also works in the second case. – Robert Page Nov 26 '20 at 12:00
  • @RitobrotoGanguly Yes, and it calls `x::print(int)`, because `char` can be implicitly converted to `int`. – molbdnilo Nov 26 '20 at 12:05
  • @molbdnilo what about case 4, as I have updated the question – Robert Page Nov 26 '20 at 12:08
  • @molbdnilo,the entire point of virtual functions is so that the derived class functions may be called instead of the base class ones – Robert Page Nov 26 '20 at 12:18
  • @RitobrotoGanguly Example 3 calls `x::print(int)` and example 4 calls `y::print(double)` since that's a virtual method that exists in the base. What part is unclear? – super Nov 26 '20 at 12:49
  • 1
    I think you are getting confused because there are 2 different mechanisms involved here. Overload resolution and virtual functions. The two doesn't have anything to do with eachother. Overload resolution is resolved at compile time and virtual functions are resolved at run time. – super Nov 26 '20 at 12:50
  • @super, I am asking for the exact look up process for case 2. Is the compiler first looking into base class and then into derived class, or is it looking into the derived class and then the base class, or if some other mechanism is involved – Robert Page Nov 26 '20 at 13:11
  • @RitobrotoGanguly Yes, I know what virtual functions are for. I also know that the function to be called is determined at runtime, not ny the compiler, and that name lookup has nothing to do with it. Your case 3 does not call `y::print(char)` but `x::print(int)`, and case 4 is the only case where you've actually overriden a virtual function. – molbdnilo Nov 26 '20 at 13:13
  • @molbdnilo, I understand your point but, then what is the exact process for selecting the function in case 2? – Robert Page Nov 26 '20 at 13:19
  • @RitobrotoGanguly I already told you. In case 2 it looks in the base class, and sees `x::print(int)`. That's the whole process. – super Nov 26 '20 at 13:20
  • In case 2, `t` has type `x*`, and `print` is found in `x`. Thus, the overloads in `x` are the candidates. `1` is an `int`, and there is a `print(int)` function in `x`, so that overload is selected by the compiler. At runtime, `x::print(int)` is called through the virtual dispatch mechanism since `y` does not override `print(int)`. – molbdnilo Nov 26 '20 at 13:22
  • @molbdnilo, by that logic in case 4 also t is of type x, then it should again call x::print(double) – Robert Page Nov 26 '20 at 13:24
  • @super, then why is the process for case 2 and case 4 different? You are saying that in case 2 it initially looks into base class and selects x::print(int) but in case 4 it selects a derived class function by looking in derived class. – Robert Page Nov 26 '20 at 13:25
  • @RitobrotoGanguly In case 4 you have overriden `print(double)`, and that is called *at runtime* through the virtual dispatch mechanism - it is not selected by the compiler. Name lookup and overload resolution is done at compile time; determining which virtual override to call happens at runtime. (If you start using the `override` specifier that was introduced in C++11, the compiler will tell when you're not overriding anything.) – molbdnilo Nov 26 '20 at 13:34
  • @molbdnilo, in case 2 I have overriden print(double), then why will the 1 be not converted to 1.0 and y::print(double) be called?, is it something like x::print(int) is getting selected at compile time so runtime polymorphism isn't happening? – Robert Page Nov 26 '20 at 14:17
  • @molbdnilo, I am sorry, but I still am not getting the process of selection. Like at runtime does the does the program look at the base class and see that x::print(double) has been overriden and then it looks at x::print(int) and sees that it has not been overriden so executes it and stops? – Robert Page Nov 26 '20 at 14:30
  • 1
    I think [How are virtual functions and vtable implemented?](https://stackoverflow.com/questions/99297/how-are-virtual-functions-and-vtable-implemented) would be helpful to you. – molbdnilo Nov 26 '20 at 15:12
  • 1
    @RitobrotoGanguly It's not. In case 4 the name lookup finds `x::print(double)` which is selected. But since `x::print(double)` is a virtual method, at runtime the derived class function will be called because the object is of type `y`. In case 2 `x::print(int)` is not a virtual function. That's the difference between the two cases. – super Nov 26 '20 at 15:30
  • 2
    As I already said, you are getting confused because you are not separating the process of name lookup/overload resolution (happends at compile-time and decides which method/function to call) and virtual dispatch. The name lookup works the same in both cases, but in case 4 you ALSO have a virtual function dispatch. In case 2 `x::print(int)` is virtual as well, but it's not overridden in the derived class. – super Nov 26 '20 at 15:33

0 Answers0