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.
Related
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;
};
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.
If I have a pure virtual function can it be overriden with a function pointer? Scenario below (I'm aware that it's not 100% syntactically correct):
#include<iostream>
using namespace std;
class A {
public:
virtual void foo() = 0;
};
class B : public A {
public:
B() { foo = &B::caseOne; }
void caseOne() { cout << "Hello One" << endl; }
void caseTwo() { cout << "Hello Two" << endl; }
void (B::*foo)();
void chooseOne() { foo = &B::caseOne; }
void chooseTwo() { foo = &B::caseTwo; }
};
int main() {
B b;
b.(*foo)();
}
EDIT: In case anyone's interested, here's how I accomplished what I wanted to do:
#include<iostream>
using namespace std;
class A {
public:
virtual void foo() = 0;
};
class B : public A {
public:
B() { f = &B::caseOne; }
void caseOne() { cout << "Hello One" << endl; }
void caseTwo() { cout << "Hello Two" << endl; }
void (B::*f)();
void chooseOne() { f = &B::caseOne; }
void chooseTwo() { f = &B::caseTwo; }
void foo() { (this->*f)(); }
};
int main() {
B b;
b.foo();
b.chooseTwo();
b.foo();
}
The output is:
Hello One
Hello Two
No. And you use this wrong. In your code you are trying to assign member-function pointer to function-pointer - it's cannot be compiled.
C++03 standard 10.3/2
If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or
indirectly from Base, a member function vf with the same name and same parameter list as Base::vf is
declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides
Base::vf.
As #ForEveR said, your code cannot compile. However, since what you actually need is the ability of switching B's implementation of foo in the runtime, we do have workaround:
#include <iostream>
using namespace std;
class A {
public:
virtual void foo() = 0;
};
class B : public A {
private:
void (B::*_f)();
public:
B() { chooseOne(); }
void caseOne() {
cout << "case one" << endl;
}
void caseTwo() {
cout << "case two" << endl;
}
void chooseOne() { _f = &B::caseOne; }
void chooseTwo() { _f = &B::caseTwo; }
void foo() {
(this->*_f)();
}
};
int main(int argc, const char *argv[])
{
A* b = new B();
b->foo();
((B*)b)->chooseTwo();
b->foo();
return 0;
}
UPDATE:
Just found the OP added his answer in the question, which is almost the same as mine. But I think calling foo through pointer instead of instance object is better, for that can exhibit the effect of polymorphism. Besides, it's better to hide f as a private member function.
I think when compile time, the syntax can NOT be compiled. You should provide an override function with the certain name and same args list.
I am having a weird problem, which I'm sure has an easy fix. I have a super class let's call it "Bird". Bird has a virtual function called chirp, which returns me 0. I also have a subclass lets call it...SomeOtherBird. SomeOtherBird is a subclass of Bird. The chirp() function for my subclass is supposed to return me 1.
So far:
Bird.Chirp() should return 0
SomeOtherBird.Chirp() should return 1
Some other bird is a subclass of bird.
Now assuming I pass in Bird into a seperate constructor, let's call it nest.
So: nest(Bird& x)
if I pass a SomeOtherBird in, and I call Chirp, it calls the virtual function of the main super-class and not of the subclass, so for example:
SomeOtherBird x;
Nest(x);
and then if I do x.chirp, the main method is called, not the one of the subclass.
How do I get the function in the sub-class to be called, and not the virtual main function?
Thanks
I worked for me.
ideone.com/RRfau
You really ought to include some example code with questions like this so we can help you.
#include <iostream>
#include <typeinfo>
class Bird
{
public:
virtual ~Bird() {}
virtual int chirp() { return 0; }
};
class SomeOtherBird : public Bird
{
public:
virtual int chirp() { return 1; }
};
void nest( Bird& x )
{
std::cout << typeid(x).name() << " says " << x.chirp() << '\n';
}
int main()
{
SomeOtherBird s;
nest( s );
Bird b;
nest( b );
}
Works fine as shown below. Perhaps you might not have made the base method virtual. Or there is something else wrong in the code, since the code was not posted, it is impossible to tell.
#include <iostream>
using namespace std;
class Bird
{
public:
Bird() {}
~Bird() {}
virtual int Chrip() { cout << "Bird version" << endl; return 0; }
};
class SomeOtherBird:public Bird
{
public:
SomeOtherBird() {}
~SomeOtherBird() {}
virtual int Chrip() { cout << "SomeOtherBird version" << endl; return 1; }
};
int nest(Bird &b)
{
b.Chrip();
}
int main()
{
SomeOtherBird s;
Bird &b = s;
int retcode = nest(b);
cout << "retcode " << retcode << endl;
}
Output:
rhdevblade1-~/cpp: ./virt
SomeOtherBird version
retcode 1
Without seeing your code it's impossible to answer you for sure. However, this sounds like you did not write "virtual Bird()" in your base class, only in the derived class. That doesn't work.
class Bird {
virtual int Bird();
};
class MoreBird : public Bird {
int Bird();
};
The virtual keyword is not required in the deriving class (although it is not good practice not to put it there even if 99.9% of the programmers are lazy and don't do it.)
class Material
{
public:
void foo()
{
cout << "Class Material";
}
};
class Unusual_Material : public Material
{
public:
void foo()
{
cout << "Class Unusual_Material";
}
};
int main()
{
Material strange = Unusual_Material();
strange.foo(); //outputs "Class Material"
return 0;
}
I would like for this to result in the "Class Unusual_Material" being displayed to the console. Is there a way I can achieve this? In my program I have a class Material from which other more specific materials are derived. The method Material::foo() represents a method in Material that is adequate for most materials, but occationally, another foo() needs to be defined for a material with unusual properties.
All objects in my program contain a Material field. In the event that they are assigned an unusual material, I would like the derived, unusual foo to be called.
This is probably either pretty easy, or impossible, but I can't figure it out either way.
Thanks
What you want is polymorphism, and to enable it for a function you need to make it virtual:
class Material
{
public:
virtual void foo() // Note virtual keyword!
{
cout << "Class Material";
}
};
class Unusual_Material : public Material
{
public:
void foo() // Will override foo() in the base class
{
cout << "Class Unusual_Material";
}
};
Also, polymorphism only works for references and pointers:
int main()
{
Unusual_Material unusualMaterial;
Material& strange = unusualMaterial;
strange.foo();
return 0;
}
/* OR */
int main()
{
Unusual_Material unusualMaterial;
Material* strange = &unusualMaterial;
strange->foo();
return 0;
}
What you have in your code snippet will slice the Unusual_Material object:
int main()
{
// Unusual_Material object will be sliced!
Material strange = Unusual_Material();
strange.foo();
return 0;
}
Still better explanation would be..
class Base
{
public:
void foo() //make virtual void foo(),have derived method invoked
{
cout << "Class Base";
}
};
class Derived: public Base
{
public:
void foo()
{
cout << "Class Derived";
}
};
int main()
{
Base base1 = Derived ();
Base1.foo(); //outputs "Class Base"
// Base object, calling base method
Base *base2 = new Derived ();
Base2->foo(); //outputs"Class Base",Again Base object calling base method
// But to have base object, calling Derived method, following are the ways
// Add virtual access modifier for base foo() method. Then do as below, to //have derived method being invoked.
//
// Base *base2 = new Derived ();
// Base2->foo(); //outputs "Class Derived" .
return 0;
}