struct struct1
{};
struct struct2:public struct1
{};
class Base
{
public:
virtual void foo(struct1 *s)
{
cout<<"foo in Base"<<endl;
}
};
class Der:public Base
{
public:
virtual void foo(struct2 *s)
{
cout<<"Foo in Der"<<endl;
}
};
int main()
{
struct2 s;
Base *b = new Der();
b->foo(&s);
}
When I call the function in main It calls the member in Base."foo in Base" gets printed. It prints "foo in Der" when the Derived class function takes struct1 pointer. But Is there any way to make it take struct2 pointer and display "foo in Der"
What you are asking for, interpreting that you mean to override the behavior of Base::foo, would be co-variant arguments to the function, and that is not possible in OO, as the derived type would be narrowing the contract of the base type, and thus it would break the Liskov Substitution Principle. You would not be able to substitute an object of type Base with an object of type Der, as the latter does not accept a struct1 object that is not a struct2 object.
When the derived type function has the same signature (i.e. also takes a struct1*), then it overrides the behavior of the Base and dynamic dispatch kicks in. But when you the signature has struct2* it does not override but rather hides the Base function.
Related
How can I call an overridden virtual function with a derived argument?
The argument I'm calling it with is of a derived class of the argument it was defined and overriden with.
//Args
struct ArgBase{
int val;
};
struct ArgDerived: ArgBase{
int derivedVal;
};
/////
struct Base {
int name;
virtual int doSomething(ArgBase a) = 0;
};
struct Derived: public Base {
int doSomething(ArgBase a){ //I want to overide Base's virtual function, so I need to pass in an ArgBase here (and not an ArgDerived)
return a.derviedVal; //<------------- how can I get this to work?
// option 1: return static_cast<ArgDerived>(a).derviedVal; does not work
// option 2: can I may be do something like "if(a is ArgDerived){....}"?
}
};
int main ()
{
Derived d;//object of derived class
ArgDerived ad; //object of derived argument class
ad.val = 25;
ad.derivedVal = 75;
std::cout << d.doSomething(ad) << std::endl; //<---------- call with derived argument ad
return 0;
}
You should accept the argument by reference or pointer for it to behave polymorphically
virtual int doSomething(const ArgBase& a) = 0;
then you can cast in your overriden function
return static_cast<const ArgDerived&>(a).derviedVal;
of course static_cast assumes that this cast is valid at runtime. If you are unsure of the derived type being passed then you'd need to use something like dynamic_cast which will throw a std::bad_cast if the reference is not of that type. Or use some other pattern, but the point being you must only static_cast if that type is appropriate at runtime.
Consider the following code:
#include <iostream>
#include<string>
using namespace std;
class Base
{
public:
virtual string print() const
{
return "This is Base class";
}
};
class Derived : public Base
{
public:
virtual string print() const
{
return "This is Derived class";
}
};
void describe(Base p)
{
cout << p.print() << endl;
}
int main()
{
Base b;
Derived d;
describe(b);
describe(d);
return 0;
}
On executing this code, it gives the output as
This is Base class
This is Base class
I had couple of doubts in this program:
The function print in class Base is a const member function, hence after inheritance, when we try to override the definition of print in Derived class, why doesn't the compiler give an error.
In this program, how we can we pass a derived class object (d) to the function which expects an argument of data Type Base.
Even if we could somehow pass the derived class object to the function, why does it print "This is Base class" instead of "This is Derived Class".
Does implicit type-conversion take place when I pass a derived class object to function describe?
I had be grateful if someone could explain me the working of this code.
The function print in class Base is a const member function, hence after inheritance, when we try to override the definition of print in Derived class, why doesn't the compiler give an error.
There is no error because the program is well-formed. It is unclear why you bring up the detail that the member function is const. Constness of a member function has no effect on whether the function can be overridden. Did you assume that const means final?
In this program, how we can we pass a derived class object (d) to the function which expects an argument of data Type Base.
Because that class Base is a public base of the Derived class, and thus the derived object is implicitly convertible to the base. The result of the conversion is a copy of the base class sub object. This is colloquially called "slicing".
Even if we could somehow pass the derived class object to the function, why does it print "This is Base class" instead of "This is Derived Class".
Because there is no derived class object inside the function. There is a copy of the base.
Does implicit type-conversion take place when I pass a derived class object to function describe?
Yes. When you pass an argument of a type that is different from the type of a non-reference parameter, there is always an implicit conversion.
Indirection is necessary for runtime polymorphism. Try the same using a reference to base as parameter and you'll see the overriding function called.
Your first question is why it did not give you an error because your function is const. Const function does not prohibit you from overriding it. If you want your function to be not overridden by derived classes you can declare that function final.
virtual string print() const final;
Now this will not be overridable by any other derived class. As far as you are concerned about the const. You can Overload your function on the basis of constness. For example, you can have.
virtual string print() const; // Does not modify anything
virtual string print(); Can modify `this`
For the second question can pass the Derived class object to a function witch expect the Base class object. But It is only possible if it is via reference or via a pointer.
void describe(const Base& p);
void describe(Base* p);
For the third question as you passed via copy, so your derived class object is narrowed to Base class. Which essentially loss all the additional information other than its Base class.
The fourth question has the same answer as 3.
This is fully functional code as you had expected to run.
#include <iostream>
#include<string>
using namespace std;
class Base
{
public:
virtual string print() const
{
return "This is Base class";
}
};
class Derived : public Base
{
public:
virtual string print() const override
{
return "This is Derived class";
}
};
void describe(const Base& p)
{
cout << p.print() << endl;
}
int main()
{
Base b;
Derived d;
describe(b);
describe(d);
return 0;
}
Here you can see I declared overridden function override to tell the compiler that this function is being overridden from its Base Class. Without this, it works as expected but it's like function hiding rather than overriding.
I understand why you cannot simply cast a derived class member function pointer to base class member function pointer as explained here.
But, given this snippet:
struct base
{
virtual void foo() = 0;
};
struct derived : base
{
void foo() override {};
};
struct invoker
{
typedef void(base::*target)();
invoker(base* b, target t)
{
(b->*t)();
}
};
template<typename B, typename D>
void (B::*cast(void (D::*method)()))()
{
return static_cast<void(B::*)()>(method);
}
derived d;
invoker bad(&d, &derived::foo); //C2664
invoker good(&d, cast<base>(&derived::foo));
I wanted to ask is it possible to decorate the base function signature so that compiler understands it is a pure virtual method and and it will be implemented somewhere across the hierarchy (otherwise I could not construct an object of type B)? I understand why I can't do this with normal functions, but IMHO in case of a pure virtual function the compiler has a guarantee it will be implemented (in case it was not done I would get an error about the class B not about the cast).
There's no need to manipulate the type of &derived::foo. One can just use &base::foo instead.
Pointers to member functions respect virtuality. This call
base* pBase = new derived;
auto pFoo = &base::foo;
(pBase->*pFoo)();
will actually call derived::foo, exactly like a simple call pBase->foo() would.
Even if there's a guarantee that it's implemented, it might use additional data members declared only in derived. A possible solution is to use function pointers and pass this as the first parameter (this also shows you why you cannot do it via virtual).
Consider the following diamond hierarchy:
struct base {
virtual void foo() = 0;
};
struct D1 : public virtual base {
virtual void foo() override;
};
struct D2 : public virtual base {
virtual void foo() override;
};
struct Derived : public virtual D1, D2 {
virtual void foo() final;
};
Now consider a scenario where a upcast is allowed from Derived::* to base::* . Which function should be invoked? The compiler loses information about which of D1::foo, D2::foo or Derived::foo you wish to call since that information has been cast away. To avoid this sort of ambiguity such an upcast is disallowed.
Why this is not legal:
class Base
{
public:
Base(){};
virtual ~Base(){};
};
class Derived : public Base{};
void takeDerived(Derived * c){};
// main
void(*ptr)(Base*) = static_cast<void(*)(Base*)>(&takeDerived); // doesn't work
// but this work ok, as well as reinterpret_cast
// void(*ptr)(Base*) = (void(*)(Base*))(&takeDerived);
Derived is a Base. Why can't it be casted in function parameter? For example, I can do this easily even without casting:
void takeBase(Base* c){};
takeBase(new Derived{});
It's just designed to be that way. A Base isn't a Derived. The is-a relationship for class derivation can't be reversed.
The type of a function parameter means "accept", while the type of an object means "fit". Casting the type of a function changes what it accepts. It's dangerous to allow a function to accept whatever isn't what it originally accepts.
Consider this code:
class Base {};
class Derived : public Base {
public:
int t;
void useDerived() {}
};
void useDerived(Derived *d){
d->useDerived();
}
What should happen if a Base object is passed?
Base b;
((void(*)(Base*))useDerived) (&b);
Even worse, what if another derivation of Base is passed?
class AnotherDerived : public Base {
public:
double t;
void useDerived() {}
};
AnotherDerived ad;
((void(*)(Base*))useDerived) (&ad);
Yes, but you're trying to do it the other way around. You cannot do
void takeDerived(Derived *c) { }
...
Base b;
takeDerived(&b);
The function pointer cast you're trying to do would enable these shenanigans; you could do
void (*ptr)(Base*) = takeDerived;
Base b;
ptr(&b); // Oops.
Then things would explode, and that would be bad.
I have a class that contains some functions (none are virtual) and 2 more classes publicly inherit that class. In both the sub classes I override the same function of the base class.
After creating objects of all three classes in main (located at the same file), I call the original function with the baseclass object and the overridden functions with the derivedclass objects.
I was expecting all 3 function calls to run the original function from the base class (since I didn't use 'virtual' anywhere in the code), but I actually get each version of that function working according to the class in which it was defined (3 different versions).
I have the classes Base & Derived as follows:
struct Base
{
void foo();
};
struct Derived : Base
{
void foo();
};
in main:
int main()
{
Derived d;
d.foo();
}
I thought d.foo() should run Base::foo() if not using 'virtual'.
This is not "overriding"... and it doesn't need to be.
struct Base
{
void foo();
};
struct Derived : Base
{
void foo();
};
int main()
{
Derived d;
d.foo();
}
If I understand you correctly, then you were expecting this to execute Base::foo(), because the functions are not virtual and therefore one does not override the other.
But, here, you do not need virtual dispatch: the rules of inheritance simply state that you'll get the right function for the type of the object you run it on.
When you need virtual dispatch/overriding is a slightly different case: it's when you use indirection:
int main()
{
Base* ptr = new Derived();
ptr->foo();
delete ptr;
}
In the above snippet, the result will be that Base::foo() is called, because the expression ptr->foo() doesn't know that *ptr is really a Derived. All it knows is that ptr is a Base*.
This is where adding virtual (and, in doing so, making the one function override the other) makes magic happen.
You cannot override something that isn't virtual. Non-virtual member functions are dispatched statically based on the type of the instance object.
You could cheat by "overriding" a function by making it an inline function calling something indirectly. Something like (in C++03)
class Foo;
typedef int foo_sig_t (Foo&, std::string&);
class Foo {
foo_sig_t *funptr;
public:
int do_fun(std::string&s) { return funptr(*this,s); }
Foo (foo_sig_t* fun): funptr(fun) {};
~Foo () { funptr= NULL; };
// etc
};
class Bar : public Foo {
static int barfun(Bar&, std::string& s) {
std::cout << s << std::endl;
return (int) s.size();
};
public:
Bar () : Foo(reinterpret_cast<foo_sig_t*>)(&barfun)) {};
// etc...
};
and later:
Bar b;
int x=b.do_fun("hello");
Officially this is not overloading a virtual function, but it looks very close to one. However, in my above Foo example each Foo instance has its own funptr, which is not necessarily shared by a class. But all Bar instances share the same funptr pointing to the same barfun.
BTW, using C++11 lambda anonymous functions (internally implemented as closures), that would be simpler and shorter.
Of course, virtual functions are in generally in fact implemented by a similar mechanism: objects (with some virtual stuff) implicitly start with a hidden field (perhaps "named" _vptr) giving the vtable (or virtual method table).