so I got this problem while trying to overload in c++:
I have those classes:
class Data
{
public:
void virtual f(){cout<<"In data!"<<endl;}
};
class A: public Data
{
public:
void f(int x){cout<<"Class A int is: "<<x<<endl;}
};
then I do:
Data *D=new A();
D->f(4);
I expect the Data's f() function to do to class A's f() function since I did it virtual, but it won't.
Any ways to make it work?
That's not the same function, the one in the derived class takes an int parameter.
That shouldn't even compile, because Data doesn't have a method called f(int).
For polymorphism to work, you need the same signature:
class Data
{
public:
void virtual f(int){cout<<"In data!"<<endl;}
// |
// dummy parameter
};
class A: public Data
{
public:
void f(int x){cout<<"Class A int is: "<<x<<endl;}
};
You need to have the same parameters when overloading. Your compiler sees doStuff(int a), doStuff(String a) and doStuff() as different functions. Be sure they all have the same parameters when you're overloading.
Overloading does not work across class boundaries.
Here is something you can do to be able to call both using an object of class A -
class Data
{
public:
void virtual f(){cout<<"In data!"<<endl;}
// |
// dummy parameter
};
class A: public Data
{
using Data::f;
public:
void f(int x){cout<<"Class A int is: "<<x<<endl;}
};
Related
When publicly inheriting a class, why can't I define a function of the base class using name of derived class if the public members of base class are inherited by that derived class?
Example:
#include <iostream>
using namespace std;
class one{
int a;
public:
void get(int);
void show();
};
class two:public one
{
int b;
public:
void getb(int);
void dis();
};
void one::get(int x) //if i write void two::get(int x) here it gives error
{
a = x;
}
void one::show() //same goes for this function why can't i define it as `void two::show()`?
{
cout << a << endl;
}
int main()
{
two ob;
int x;
cin >> x;
ob.get( x );
ob.show();
}
So if if all public member functions of class one are inherited by class two, why can't I define functions of class one using name of class two ?
Why ?
In the class definition, you say that two inherits from one. So it will have the following public members:
void get(int); publicly inherited from one
void show(); publicly inherited from one
void getb(int); own member
void dis(); own member
You can define only the own member functions of two, here two::getb(int) and two::dis(). But you can't define two::show() because it was defined in one and you did not tell the compiler that you wanted it.
Is there a way to do have a different version of the inherited functions ?
If you'd define the class as follows:
class two:public one
{
int b;
public:
void getb(int);
void dis();
void show(); //yes you can, but you'll have to define it
};
then you would have the following public members:
void get(int); publicly inherited from one
void one::show(); publicly inherited from one but hidden
void show(); own member
void getb(int); own member
void dis(); own member
you could define the following:
void two::show() //no problem !!
{
cout << "two's version" << endl;
}
You could even choose in main() which one you want to call:
ob.get( x ); // one::get(), because there's no two::get()
ob.show(); // by default two::show(), because ob is a two
ob.one::show(); // yes you can !!
Here an online demo
Want polymorphism ?
In all the code above, the function invoked depend on the type used to access the object:
one *pob = &ob; // a one pointer can point to a two object
pob->show(); // but this will invoke one::show()
If you'd prefer the right function be called depending on the real type of the object, and not the type assumed from the type declaration, you'd need to use virtual functions and override them:
class one{
... (the rest as before) ...
virtual void show();
};
class two:public one
{
... (the rest as before) ...
void show() override;
};
Then, whenever you invoke show(), the correct function will be called (online example), unless you specifically inkove a precisely specified version by using a fully qualified identifier.
Method func from DerivedClass override the method func and all its overloads from BaseClass.
#include <cstdio>
class BaseClass
{
public:
void func(int a){puts("BaseClass::func(int)");};
void func(int a, int b){puts("BaseClass::func(int, int)");};
void func(int a, int b, int c){puts("BaseClass::func(int, int, int)");};
//...
};
class DerivedClass : public BaseClass
{
public:
void func(int a){puts("DerivedClass::func(int)");}
//...
};
int main()
{
DerivedClass obj;
obj.func(0);
obj.func(0, 0); // error
obj.func(0, 0, 0); // error
return 0;
}
How can I fix this code to end up on the screen was derived:
DerivedClass::func(int)
BaseClass::func(int, int)
BaseClass::func(int, int, int)
Edit 1
In functions main should not change anything
The derived class's member function doesn't override the base class ones, it hides them. To bring them all to scope, use a using declaration:
class DerivedClass : public BaseClass
{
public:
void func(int a){puts("DerivedClass::func(int)");}
using BaseClass::func;
//...
};
Live example
It's by design: the phenomenon is called "name hiding".
[Short answer]:
C++ doesn't like the idea that a long-standing behavior as calling one base-function with a specific set of parameters can be modified in one of your subclasses and chose to hide all overloads in every base class to solve this.
[Long answer] here:
https://stackoverflow.com/a/1629074/1938163
As a workaround you can cast the object to the appropriate base and call the functions you need (there's a cast penalty though), or better call the function you need directly by specifying its base class
int main()
{
DerivedClass obj;
obj.func(0);
obj.BaseClass::func(0,0);
return 0;
}
Live Example
or you can un-hide them with a "using directive"
class DerivedClass : public BaseClass
{
public:
void func(int a){puts("DerivedClass::func(int)");}
using BaseClass::func;
//...
};
Live Example
Let's say I have an abstract base class Base with a virtual function doSomething()
There are two derived classes, one of which takes no parameters in doSomething() while the other takes a structure and an integer as a parameter.
A function in another class (SomeClass) calls doSomething() using a Base* variable.
It also needs to pass the parameters i mentioned for DerivedTwo.
How do i choose the prototype without using an if-else to check for the object's class at run-time?
Thank you.
class Base {
public:
void virtual doSomething();
}
class DerivedOne : Base {
public:
void doSomething(int a,struct b);
}
class DerivedTwo : Base {
public:
void doSomething();
}
You are wanting to change the parameter list of a virtual method in a derived class. This cannot be done. Usually when you find yourself wanting to do this it indicates that your class hierarchy design is incorrect.
The naive attempts to tackle this usually involve adding something to the base class which is only meaningful for certain derived classes. This violates the principles of good design.
There are many different ways to tackle the issue more properly, but it's hard to advise on the basis of this artificially constructed example.
One way to do this would be:
class Base {
public:
Base();
virtual ~Base();
virtual void doSomething();
};
class DerivedOne : public Base {
public:
DerivedOne();
void doSomethingElse(int a,struct b);
};
class DerivedTwo : public Base {
public:
DerivedTwo();
virtual void doSomething();
};
You could then use dynamic_cast to determine the type at runtime since you seem to have a type-conditional expression someplace in SomeClass. The methods are not equal and fundamentally distinct. Also, DerivedOne::doSomething would hide Base::doSomething.
Update
As the others had already stated, it's often a bad smell if your program relies on type-conditional expressions. Since your example does not have enough context to offer appropriate solutions, it's hard for us to help you in this regard. If you are interested in removing the type-conditional, one of many potential solutions to this problem would be:
class Base {
public:
Base();
virtual ~Base();
virtual void doSomething();
};
class DerivedOne : public Base {
public:
DerivedOne();
// ...
virtual void doSomething(); // << no parameters required.
// they have moved to member data:
private:
int a;
b another;
};
class DerivedTwo : public Base {
public:
DerivedTwo();
virtual void doSomething();
};
then you could remove the type-conditional expression from your program. If you'd like help in this regard, feel free to ask here or open a new question if you feel it is more appropriate.
If you need to pass these variables for both derived types, just declare them same everywhere, like this:
class Base {
public:
void virtual doSomething(int a,struct b);
}
class DerivedOne : Base {
public:
void doSomething(int a,struct b);
}
class DerivedTwo : Base {
public:
void doSomething(int a,struct b);
}
If you need to use parameters for one type and not for the other type, then what you need is not a class hierarchy. You will need to elaborate your problem more in that case.
Can we solve this problem like this? :
class Base {
public:
void virtual doSomething();
void virtual doSomething(int a,struct b);
}
class DerivedOne : Base {
public:
void doSomething(int a,struct b);
}
class DerivedTwo : Base {
public:
void doSomething();
}
in your exmple you can use RTTI instead of if/else so you instantiate DerivedOne and DerivedTwo then you cast the Base pointer to both (DerivedOne and DerivedTwo) so the result is one of them is NULL. then you check wether the desired Derived object is not NULL and if it is you call the function:
DerivedOne *pDrvOne=dynamic_cast<DerivedOne*>(pBase);
DerivedTwo *pDrvTwo=dynamic_cast<DerivedTwo*>(pBase);
then: if(pDrvOne)pDrvOne->deSo,ething(a,b); if(pDrvTwo) pDrvTwo->doSomething();
* Remeber the use of RTTI will undermine the principles of polymorphism.
in your example you didn't overload doSomething() in DerivedOne subclass: "to overload a function is to use the same signature(name of function and the same number and type of parameters)". but you just overload it in DerivedTwo. thus consider this example:
Base *pBs;
pBs=new DerivedOne; pBs->doSomething(a,b); the result a call to base doSomthing!!!
*The solution is to try to understand the problem your class is going to solve.
Similar to Taras's example .. just add 'default values' to Base's and DerivedTwo's prototype in Taras's example. That way rest of the code which is using Base class or DerivedTwo class won't have to change.
What does it mean to have a using inside a class definition?
class myClass {
public:
[...]
using anotherClass::method;
};
That declaration unhides a base class member. This is most often used to allow overloads of a member function. Example:
class Base {
public:
void method() const;
};
class Derived : public Base {
public:
void method(int n) const;
// Without the using, you would get compile errors on d.method();
using Base::method;
};
The case I've seen it:
class A
{
void foo(int);
void foo(float);
}
class B : public A
{
void foo(string);
}
B b;
b.foo(12); // won't work!
Because I have implemented a new foo function in B with a different signature it hides the foo functions from A. In order to override this behavior I would do:
class B : public A
{
void foo(string);
using A::foo;
}
Most often, syntax like this is used like so:
class derived : public base {
public:
[...]
using base::method;
};
The using declaration here unhides a member declaration from the parent class. This is sometimes necessary if another member declaration in derived may hide the member from base.
If anotherClass is a base class that contains a member function like
virtual void f();
and you decide to overload the function in the derived class like
virtual void f(int);
it "hides" f() in the base class. Calling f() through a pointer to the derived class for example, would result in an error, since the compiler does not "see" the version of f() taking no arguments from the base class anymore.
By writing
using Base::f;
you can bring the base classes function back into scope, thus enabling overload resolution as you might have expected it to work in the first place.
If I have a code like this:
struct A {
virtual void f(int) {}
virtual void f(void*) {}
};
struct B : public A {
void f(int) {}
};
struct C : public B {
void f(void*) {}
};
int main() {
C c;
c.f(1);
return 0;
}
I get an error that says that I am trying to do an invalid conversion from int to void*. Why can't compiler figure out that he has to call B::f, since both functions are declared as virtual?
After reading jalf's answer I went and reduced it even further. This one does not work as well. Not very intuitive.
struct A {
virtual void f(int) {}
};
struct B : public A {
void f(void*) {}
};
int main() {
B b;
b.f(1);
return 0;
}
The short answer is "because that's how overload resolution works in C++".
The compiler searches for functions F inside the C class, and if it finds any, it stops the search, and tries to pick a candidate among those. It only looks inside base classes if no matching functions were found in the derived class.
However, you can explicitly introduce the base class functions into the derived class' namespace:
struct C : public B {
void f(void*) {}
using B::f; // Add B's f function to C's namespace, allowing it to participate in overload resolution
};
Or you could do this:
void main()
{
A *a = new C();
a->f(1); //This will call f(int) from B(Polymorphism)
}
Well I think first of all you did not understand what virtual mechanism or polymorhism. When the polymorphism is achieved only by using object pointers. I think you are new to c++. Without using object pointers then there is no meaning of polymorphism or virtual keyword use base class pointer and assign the desired derived class objects to it. Then call and try it.