I am trying to overload a virtual function, like this:
#include<iostream>
#include<string>
using std::cout;
using std::endl;
using std::string;
class Base{
public:
virtual void show(int x){
cout << "Showing int as Base: " << x << endl;
}
};
class Derived : public Base{
public:
using Base::show;
virtual void show(string s){
cout << "Showing string as Derived: " << s << endl;
}
};
int main(){
Derived x;
Base& ref = x;
ref.show(3);
ref.show(string("hi")/*in case the compiler refuses to implicitly convert const char* to std::string*/);
}
However, GCC complains error: cannot convert 'std::string' {aka 'std::__cxx11::basic_string<char>'} to 'int', and says note: initializing argument 1 of 'virtual void Base::show(int)'
It seems like gcc just ignored the Derived's overload of show.
I suspect that overloading together with polymorphism is just a BIT too much to handle for the compiler, since that would require storing the type information in the vtable as well, which MAY be not possible.
But then, what should I do to mimic this behaviour?
This worked:
#include<iostream>
#include<string>
#include<any>
using std::cout;
using std::endl;
using std::string;
using std::any;
using std::any_cast;
class Base{
public:
virtual void show(int x){
cout << "Showing int as Base: " << x << endl;
}
virtual void show(any x) = 0;
};
class Derived : public Base{
public:
using Base::show;
virtual void show(any s) override{
if(s.type() != typeid(std::string)){
if(s.type() != typeid(int)){
throw "SOME_ERROR_INDICATING_INVALID_FUNCTION_CALL";
}
Base::show(any_cast<int>(s));
return;
}
cout << "Showing string as Derived: " << any_cast<string>(s) << endl;
}
};
int main(){
Derived x;
Base& ref = x;
ref.show(3);
ref.show(string("hi")/*invokes show(any) override */);
}
but it seems really stupid. Is there any other workaround?
EDIT: adding virtual void show(string x)=0; to base is NOT desireable. This is just a MRE, and in the real program I have lots of derived classes, and I don't want to add a pure virtual function in Base for each of those customizations.
The problem is that you're calling show through a reference to a base object while passing a std::string as an argument but the base class doesn't have any such method so this call can't succeed.
To solve this you can add a declaration for virtual void show(string s) =0; inside the base class.
class Base{
public:
virtual void show(int x){
cout << "Showing int as Base: " << x << endl;
}
//added this declaration for making it pure virtual
virtual void show(string s)=0;
};
Related
I am trying to deal with abstract class argument, trying to figure out what to do, after running this code below getting the error : "In function 'int main()': 67:12: error: expected primary-expression before ')' token"
#include <iostream>
#include <string>
using namespace std;
class base1 {
protected:
int i;
public:
base1(int x) {
i=x;
cout << "Constructing base1\n";
}
virtual ~base1() {
cout << "Destructing base1\n";
}
};
class derived: public base1 {
int j;
public:
derived(int x, int y): base1(y){
j=x;
cout << "Constructing derived\n";
}
~derived() {
cout << "Destructing derived\n";
}
void show() {
cout << i << " " << j << " " << "\n";
}
};
class Isolver
{
public :
Isolver(){};
virtual ~ Isolver(){};
virtual void x(base1* pboard)=0;
};
class vr:public Isolver
{
void x(base1* pboard)
{
cout << "My virtual fun and base constructor are not working\n"<<endl;
};
};
int main()
{
vr obj;
obj. x(10, );
derived ob(3,4);
ob.show();
return 0;
}
Like Paul Rooney pointed out the comma inside obj.x(10,) should not be there because with the comma the compiler is expecting two arguments and since there is nothing after the comma it shows an error.
This is what you need to do inside main:
vr obj;
base1 b(1);
obj. x(&b);
or this:
vr obj;
derived ob(3,4);
obj. x(&ob);
ob.show();
and inside class vr
class vr:public Isolver
{
public:
void x(base1* pboard)
{
cout << "My virtual fun and base constructor are not working\n"<<endl;
}
};
I am facing the following problem with my code:
#include <iostream>
using namespace std;
class Base {
public:
virtual void sayHello()=0;
};
class Impl1 : public Base {
public:
void sayHello() { cout << "Hi from Impl1" << endl; }
};
class Impl2 : public Base {
public:
void sayHello() { cout << "Hi from Impl2" << endl; }
};
void sayHello(Impl1 *i) {
cout << "Impl1 says: ";
i->sayHello();
}
void sayHello(Impl2 *i) {
cout << "Impl2 says: ";
i->sayHello();
}
int main()
{
Impl1 *i1 = new Impl1();
Base *b = i1;
sayHello(b);
return 0;
}
And here the compiler complains about the sayHello(b); line in the
code.
"call of overloaded 'sayHello(Base*&)' is ambiguous"
Is there a way to solve this problem?
EDIT:
I basically want to pass my object to a function that does some calculations based on the type of the object. My object intentionally lacks of information in order to make the needed calculations. So Impl1 and Impl2 just contain some basic data, without the knowledge of more data needed to do the calculations.
Overload resolution is performed at compile time. It means for sayHello(b);, the compiler only know that the type of b is Base*, it won't and can't know that b is pointing to a Impl1 object actually. Then results in ambiguous call; converting Base* to Impl1* or Impl2* is equivalent rank for the call.
PS: might be OT, but for you code sample, a function taking a Base* would work fine; dynamic dispach will take effect.
class Base {
public:
virtual void sayHello()=0;
};
class Impl1 : public Base {
public:
void sayHello() { cout << "Hi from Impl1" << endl; }
};
class Impl2 : public Base {
public:
void sayHello() { cout << "Hi from Impl2" << endl; }
};
void sayHello(Base *i) {
cout << "Some derived class of Base says: ";
i->sayHello();
}
int main()
{
Impl1 i1;
Impl2 i2;
Base *b = &i1;
sayHello(b); // "Hi from Impl1"
b = &i2;
sayHello(b); // "Hi from Impl2"
return 0;
}
If you need to know the dynamic type at run-time, you can use dynamic_cast. e.g.
Base *b = /* something */;
Impl1 * pi1 = dynamic_cast<Impl1*>(b);
if (pi1 != nullptr) sayHello(pi1);
Since overloads are resolved at compile time, you have to supply the compiler with the exact type in order for the overload resolution to succeed.
In order to dispatch on the type, add a virtual member function to the Base, and use it to choose the overload:
class Base {
public:
virtual void sayHello()=0;
virtual void callSayHello() = 0;
};
class Impl1 : public Base {
public:
void sayHello() { cout << "Hi from Impl1" << endl; }
void callSayHello() {sayHello(this); }
};
class Impl2 : public Base {
public:
void sayHello() { cout << "Hi from Impl2" << endl; }
void callSayHello() {sayHello(this); }
};
void sayHello(Impl1 *i) {
cout << "Impl1 says: ";
i->sayHello();
}
void sayHello(Impl2 *i) {
cout << "Impl2 says: ";
i->sayHello();
}
...
b->callSayHello();
Note that implementations of callSayHello are identical, but you cannot place them into Base class, because the type of this would be different.
Note: the idea for this implementation is borrowed from C++ implementation of the Visitor Pattern.
Get rid of the two free-standing functions and call b->sayHello(); directly:
Impl1 *i1 = new Impl1();
Base *b = i1;
b->sayHello();
Or use an ugly workaround with dynamic_cast:
Impl1 *i1 = new Impl1();
Base *b = i1;
sayHello(dynamic_cast<Impl1*>(b));
The need to resort to dynamic_cast often suggests an error in the class design. This may very well be the case here. Chances are that you should never have introduced a supposedly object-oriented base class in the first place.
Note also that you do not call delete at the end. If you do, you will need a virtual destructor in Base.
I was playing c++ rule. I hit an error but i can't explain it. please help to explain why the compilation error happen. BTW, I am not interesting at fixing the problem. Thanks
Q1 why the name hiding doesnt work in the case? for example, if we remove lineA's keyword virtual.the compilation will works
Q2 after added a function in case2, the compilation goes through.
please help explain Q1 and Q2.
#include
using namespace std;
class base
{
public:
virtual int func() // lineA
{
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()
{
return 0;
}
output:
main.cpp:18:14: error: conflicting return type specified for 'virtual double derived::func()'
double func()
^
main.cpp:8:19: error: overriding 'virtual int base::func()'
virtual int func()
case 2:
#include <iostream>
using namespace std;
class base
{
public:
virtual int func()
{
cout << "vfunc in base class\n";
return 0;
}
// new added
virtual double func(int)
{
return 0.0;
}
};
class derived: public base
{
public:
double func(int)
{
cout << "vfunc in derived class\n";
return 0;
}
};
int main()
{
return 0;
} ^
When you override a function, your new implementation must be callable whenever the original was. The base function here returns an int. That means any caller will expect an int.
The error occurs because your overriding function is returning a double instead of an int.
Well as the compiler error states you have defined different return types for func(). You may think that this should be handeled by C++ overloading, but overloading can only be done on input parameters not on return values.
For example:
class base
{
public:
virtual int func(int param)
{
cout << "vfunc in base class\n";
return 0;
}
};
class derived: public base
{
public:
double func(double param)
{
cout << "vfunc in derived class\n";
return 0;
}
};
In this code func is overloaded in derived since it has another type for the input param.
This is kind of a specific question that I had not been able to find a solution to for quite a while. I have this code:
#include <iostream>
using namespace std;
class Mammal
{
public:
Mammal() {cout << "Mammal Constructor\n";}
virtual ~Mammal() {cout << "Mammal Destructor\n";}
virtual void Run() {cout << "Mammal Ran One Space\n";}
protected:
int mammalDistance;
};
class Horse : public Mammal
{
public:
Horse() {cout << "Horse Constructor\n";}
~Horse() {cout << "Horse Destructor\n";}
void Run() {cout << "Horse Ran One Space\n";}
void Run(int distance) {horseDistance = distance;
cout << "Horse Ran " << horseDistance << " Spaces\n";}
protected:
int horseDistance;
};
int main()
{
Mammal *pHorse = new Horse;
pHorse->Run(5);
delete pHorse;
return 0;
}
Now this code works if I take the void Run(int horseDistance) and move it up into Mammal but I wanted to know if there was a way to keep it in horse without it remaining hidden.
Edit: I mean it compiles and works as intended if I take the function that accepts input and move it up into Mammal instead of having it within the Horse class like it is currently.
Yes I would like it if it could change the value of horseDistance when it is being passed in.
Edit: O I get what your saying. I edited the code.
You have two options. One is to keep track of the fact that your pointer is a horse:
int main()
{
Horse *pHorse = new Horse;
pHorse->Run(5);
delete pHorse;
return 0;
}
The other is to declare a virtual function in Mammal:
virtual void Run(int mammalDistance) = 0;
I'd pick option #1 if horses were the only things running specific distances, option #2 otherwise.
Mammal *pHorse = new Horse;
pHorse->Run(5);
Doesn't work because there is no member function in Mammal with the signature void Run(int). More precise: the function void Run(int) given in the Horse class is not an override for the function void Run() in Mammal, because of the different signatures.
You should consider adding void Run(int) to the Mammal interface, if it is a function more subclasses will implement.
Now you know that pHorse is a Horse, but for the compiler, it is different.
The only way to do it is to check with dynamic cast if pHorse is a horse and then cast it to a Horse* and cast the method Run(5).
Horse* pHorse2=dynamic_cast<Horse*>(pHorse);
if(pHorse2!=NULL){
pHorse2->Run(5);
}else{
pHorse->Run();
}
I think you're looking for polymorphism here. All your derived Mammals simply have to implement getDistance() and setDistance() and also can implement getAnimal() to provide a name. I think there's still some room for improvement on the design, but you'll be getting the hang of polymorphism this way. Something like this perhaps:
#include <iostream>
using namespace std;
class Mammal
{
public:
Mammal() {cout << "Mammal Constructor\n";}
virtual ~Mammal() {cout << "Mammal Destructor\n";}
virtual void Run() {cout << getAnimal() << " Ran " << getDistance() << " Space\n";}
virtual void Run(int p_distance)
{setDistance(p_distance);
cout << getAnimal() << " Ran " << getDistance() << " Spaces\n";}
protected:
virtual void setDistance(int p_distance) {mammalDistance = p_distance;}
virtual int getDistance() {return mammalDistance;}
virtual string getAnimal() {return "Mammal";}
int mammalDistance;
};
class Horse : public Mammal
{
public:
Horse() {cout << "Horse Constructor\n";}
~Horse() {cout << "Horse Destructor\n";}
protected:
int horseDistance;
virtual string getAnimal() {return "Horse";}
};
int main()
{
Mammal *pHorse = new Horse;
pHorse->Run(5);
delete pHorse;
return 0;
}
My program was:-
#include < iostream.h>
#include < conio.h>
struct base
{
protected:
void get()
{
cin>>a>>b;
}
public:
base(int i=0, int j=0);
void put()
{
cout << a << '\t' << b << "\tput 1";
}
int a,b,c;
~base()
{
cout << "base destroyed";
}
};
class deri : protected base
{
int c,d;
char w;
int ans;
public:
deri(int r=7, int s=0)
: base(r,s)
{
c=r;
d=s;
cout << "\nDerived invoked\n";
}
void put()
{
cout << c << '\t' << d << '\t' << a << '\t' << b;
}
};
class d2 : protected deri
{
public:
d2() {}
void start();
void add()
{
get(); // ERROR HERE: Implicit conversion of 'd2 *' to 'base *' not allowed
}
~d2(){}
};
void d2::start()
{
put();
}
base::base(int i, int j)
{
a=i;
b=j;
cout << "\nbase invoked\n";
cout << "Enter a,b: ";
get();
}
void main()
{
clrscr();
getch();
}
CAN anyone explain what the error msg means?
You are probably using an old compiler as you're including <iostream.h> instead of the new standard <iostream> and you aren't using namespace std.
After fixing this, adding the line using namespace std; on top and commenting out clrscr() your code compiles fine on MSVC8.
Do you have a clear reason to use protected derviation ? If not, I'd suggest using public derviation instead. protected derviation is something really quite complicated and uncommon.
When you derive a base class using protected or private then your derived class is not treated as base class and compiler will not perform implicit type conversion in that case.
Derived class in not base class in case of private or protected inheritance.
whereas in case of public inheritance every derived class is a base class .
Try out explicit type casting in the function or make inheritance public.