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.
Related
Consider the example below:
#include <iostream>
using namespace std;
class base
{
public:
virtual int func()
{
cout << "vfunc in base class\n";
return 0;
}
};
class derived: public base
{
public:
double func()
{
cout << "vfunc in derived class\n";
return 0;
}
};
int main()
{
base *bptr = new derived;
bptr->func();
return 0;
}
The compiler gives an error for the above code that there is conflicting type for the overriden function. Why is it not possible to override a function in the derived class with a different return type ?
I believe, in-order to override a function, the base class virtual method needs to be redefined in the derived class. To redefine a method, the signatures of the methods has to be the same. Since return type is not part of the signature, i believe even if there is difference in return type, the method will still be redefined? In that case for the code above, virtual function func is redefined in the derived class with a different return type. But the compiler throws an error. Is my understanding correct?
Overriding essentially means that either the Base class method or the Derived class method will be called at run-time depending on the actual object pointed by the pointer.
It implies that:
i.e: Every place where the Base class method can be called can be replaced by call to Derived class method without any change to calling code.
In order to achieve this the only possible way is to restrict the return types of the overriding virtual methods to return the same type as the Base class or a type derived from that(co-variant return types) and the Standard enforces this condition.
If the above condition was not in place it would leave a window to break the existing code by addition of new functionality.
In order to override a virtual function, the return value must be exactly the same*. C++ will not automatically convert between double and int here - after all, how would it know what return type you want when calling from a derived class pointer? Note that if you change part of the signature (parameters, const-ness, etc), then you can change the return value as well.
* - strictly speaking, it must be 'covariant'. What this means is that the type you return must be a subset of the parent function's return type. For example, if the parent class returns a base *, you could return a derived *. Since deriveds are simultaneously also bases, the compiler lets you override in this manner. But you can't return totally unrelated types such as int and double; just because there's an implicit conversion doesn't mean the compiler will let you do this kind of override.
See this question. To summarize, you can only override a virtual function using a different return type if the types are covariant.
If you want to override, you should try to use template.
See the following:
#include <iostream>
using namespace std;
class base
{
public:
template<typename X> X func()
{
cout << "vfunc in base class\n";
return static_cast<X>(0);
}
};
class derived: public base
{
public:
template<typename X> X func()
{
cout << "vfunc in derived class\n";
return static_cast<X>(2);
}
};
int main()
{
derived *bptr = new derived;
cout << bptr->func<int>() << endl;
cout << dynamic_cast<base*>(bptr)->func<int>() << endl;
derived *bptr2 = new derived;
cout << bptr->func<double>() << endl;
cout << dynamic_cast<base*>(bptr)->func<int>() << endl;
return 0;
}
Of course, you dont need to declare it on two different class that way, you could do:
class base
{
public:
int func()
{
cout << "vfunc in base class\n";
return 0;
}
double func(){
cout << "vfunc for double class\n";
return 2.;
}
};
Overriding is not posssible ,as the signatures are same and the only difference is the return value. The basic purpose of overriding is polymorphism but it is not possible in the above example
I have a function that accepts a shared pointer of type Base and then std::dynamic_pointer_cast to a derived type. However, the derived pointer is a NULL and I can't see why. I have made sure to include a virtual destructor in my base class. I do not want to use a static cast as this cannot guarantee that my derived member variables and functions are preserved?
The code is as follows:
Base Class:
class Base
{
public:
mType get_type()
{
return msg_type;
}
void set_type(mType type)
{
msg_type = type;
}
virtual ~cMsg() = default;
protected:
mType msg_type;
message msg;
};
Derived Class:
class Derived : public Base
{
public:
void set_i(int j)
{
i = j;
}
int get_i()
{
return i;
}
private:
int i;
};
Function performing cast:
void callback(std::shared_ptr<Base> msg_received)
{
std::cout<< "Callback called\n";
auto real_msg = std::dynamic_pointer_cast<Derived>(msg_received);
if (real_msg != NULL)
{
std::cout << "i value is: " << real_msg->get_i() << "\n";
}
}
Function creating the Derived object and calling the function:
int main()
{
Derived test_msg;
test_msg.set_i(1);
test_msg.set_type(mSystem::TEST_MSG);
std::shared_ptr<Base> msg_ptr = std::make_shared<Base>(test_msg);
callback(msg_ptr);
return 0;
}
Any help would be appreciated.
Edit: Corrected typo
You're totally slicing. Your dynamically allocated object (managed by that shared pointer) is just a Base, copy constructed from a Derived. You can't "get the Derived back" afterwards any more than you can design a sports car with construction plans only for one of its wheels.
I think your key confusion here is in thinking that make_shared makes something shared. It doesn't. It makes something new that will be shared.
You are making shared_ptr of type Base, even if you provide it with object of type Derived. Keep in mind, all make_shared does (after allocating memory using allocator) is calling a constructor of type specified with the arguments provided to make_shared.
In your case, it creates an object of type Base, and gives it an instance of Derived. Base copy constructor is than called, passed Derived object implicitly converted to the const reference to Base.
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.
Why does this code not compile? (gcc 4.7.0)
// Class with a simple getter/setter pair.
class Base {
public:
Base () : m_Value(0) { }
virtual ~Base () { }
// Getter
virtual int value () { return m_Value; }
// Setter
virtual void value (int Val) { m_Value = Val; }
private:
int m_Value;
};
// Derived class overrides the setter.
class Derived : public Base {
public:
void value (int Val) {
// do some stuff here...
}
};
int main()
{
Derived * instance = new Derived();
int x = instance->value(); // ERROR
return 0;
}
Build log:
test.cpp: In function 'int main()':
test.cpp:29:25: error: no matching function for call to 'Derived::value()'
test.cpp:29:25: note: candidate is:
test.cpp:21:7: note: virtual void Derived::value(int)
test.cpp:21:7: note: candidate expects 1 argument, 0 provided
Why does the compiler fail to see 'int value()' from Base when using Derived*?
Changing
Derived * instance = new Derived();
to
Base * instance = new Derived();
works (but I need the derived pointer in my case).
Also renaming the base getter/setter functions to say getValue() and setValue(int) works. I can use various workarounds for my code, but I was just curious as to why this code fails to compile.
This is how the language works: When a child class overrides a member of a name it hides all the non-overridden names in the parent. This is to prevent accidentally combining base and parent methods that should be overridden as sets.
You can put using Base::value; in your child class to bring in the parent methods.
The function value in the derived class hides the function in the base class.
You need to bring the base class functions into the scope of the derived class as:
class Derived : public Base {
public:
using Base::value; //<---- note this
void value (int Val) {
// do some stuff here...
}
};
Besides the other answers given, in addition to adding using Base::value in the child class, you can also do the following,
int x = instance->Base::value();
Where you specifically tell the compiler to use Base's value function. Although technically this works, it forces a bit of indirection and if you see yourself doing this often you may want to rethink how you are structuring your code.
Consider the example below:
#include <iostream>
using namespace std;
class base
{
public:
virtual int func()
{
cout << "vfunc in base class\n";
return 0;
}
};
class derived: public base
{
public:
double func()
{
cout << "vfunc in derived class\n";
return 0;
}
};
int main()
{
base *bptr = new derived;
bptr->func();
return 0;
}
The compiler gives an error for the above code that there is conflicting type for the overriden function. Why is it not possible to override a function in the derived class with a different return type ?
I believe, in-order to override a function, the base class virtual method needs to be redefined in the derived class. To redefine a method, the signatures of the methods has to be the same. Since return type is not part of the signature, i believe even if there is difference in return type, the method will still be redefined? In that case for the code above, virtual function func is redefined in the derived class with a different return type. But the compiler throws an error. Is my understanding correct?
Overriding essentially means that either the Base class method or the Derived class method will be called at run-time depending on the actual object pointed by the pointer.
It implies that:
i.e: Every place where the Base class method can be called can be replaced by call to Derived class method without any change to calling code.
In order to achieve this the only possible way is to restrict the return types of the overriding virtual methods to return the same type as the Base class or a type derived from that(co-variant return types) and the Standard enforces this condition.
If the above condition was not in place it would leave a window to break the existing code by addition of new functionality.
In order to override a virtual function, the return value must be exactly the same*. C++ will not automatically convert between double and int here - after all, how would it know what return type you want when calling from a derived class pointer? Note that if you change part of the signature (parameters, const-ness, etc), then you can change the return value as well.
* - strictly speaking, it must be 'covariant'. What this means is that the type you return must be a subset of the parent function's return type. For example, if the parent class returns a base *, you could return a derived *. Since deriveds are simultaneously also bases, the compiler lets you override in this manner. But you can't return totally unrelated types such as int and double; just because there's an implicit conversion doesn't mean the compiler will let you do this kind of override.
See this question. To summarize, you can only override a virtual function using a different return type if the types are covariant.
If you want to override, you should try to use template.
See the following:
#include <iostream>
using namespace std;
class base
{
public:
template<typename X> X func()
{
cout << "vfunc in base class\n";
return static_cast<X>(0);
}
};
class derived: public base
{
public:
template<typename X> X func()
{
cout << "vfunc in derived class\n";
return static_cast<X>(2);
}
};
int main()
{
derived *bptr = new derived;
cout << bptr->func<int>() << endl;
cout << dynamic_cast<base*>(bptr)->func<int>() << endl;
derived *bptr2 = new derived;
cout << bptr->func<double>() << endl;
cout << dynamic_cast<base*>(bptr)->func<int>() << endl;
return 0;
}
Of course, you dont need to declare it on two different class that way, you could do:
class base
{
public:
int func()
{
cout << "vfunc in base class\n";
return 0;
}
double func(){
cout << "vfunc for double class\n";
return 2.;
}
};
Overriding is not posssible ,as the signatures are same and the only difference is the return value. The basic purpose of overriding is polymorphism but it is not possible in the above example