c++ double pointer polymorphism - c++

I'm trying to create an array of pointers using polymorphism. I will have the array of the superclass point to multiple subclasses. Is there anyway of doing this and still using a method from the subclass? Here's a sample code:
#include <iostream>
class Test1
{
public:
Test1()
: x(1)
{}
int get_x()
{
return x;
}
private:
int x;
};
class Test2 : public Test1
{
public:
Test2()
: y(2)
{}
void print()
{
std::cout << get_x() << ' ' << y << std::endl;
}
private:
int y;
};
class Test3 : public Test1
{
public:
Test3()
: y(3)
{}
void print()
{
std::cout << get_x() << ' ' << y << std::endl;
}
private:
int y;
};
int main()
{
Test1** test = new Test1*[2];
for (int i = 0; i < 2; i++)
{
if (i % 2 == 0)
{
test[i] = NULL;
test[i] = new Test2;
}
else
{
test[i] = NULL;
test[i] = new Test3;
}
}
test[0]->print(); // ERROR. Is this even possible?
test[1]->print(); // ERROR. Is this even possible?
return 0;
}
Thank you I've only been coding for about 8 months.

test[0]->print(); // ERROR. Is this even possible?
In general, yes. However, not with your code.
If Test1 is going to be your base class and you're going to use new then it must have a virtual destructor (e.g., virtual ~Test1() {})
This is necessary for delete to work correctly when deleting a derived type via a pointer to the base class
Any function you want to call using a pointer to the base class must exist on the base class (i.e., you need a print function in Test1)
If you want the derived classes to have their own implementation of print then it must be declared virtual in the base class (e.g., virtual void print();)
If it dosn't make sense for Test1 to have an implementation of the print function then it can declare it pure virtual and not provide an implementation (e.g., virtual void print() = 0;) thus making it an abstract class

It would be if Test1 had such a member function named print. Your code doesn't compile as-is because Test::print doesn't exist. So at the very least, you will have to define that member function. For it to be truly polymorphic, as the intent of the question suggests, you should make Test::print a virtual member function so that Test2's and Test3's implementations of that function would get called instead:
class Test1 {
...
virtual void print() {
std::cout << "Test1" << std::endl;
}
...
};
For more information, see this tutorial on virtual functions.

Related

Calling overridden function and using overloaded variable from base class

I have two base classes and derivered versions that overload / override certain parts like this:
class base
{
public:
int X = 1;
};
class deriv : public base
{
public:
int X = 2;
};
class A
{
public:
base K;
virtual void doSmth()
{
std::cout << "A" << std::endl;
smthElse();
}
virtual void smthElse()
{
std::cout << K.X << std::endl;
}
};
class B : public A
{
public:
deriv K;
void doSmth()
{
std::cout << "B" << std::endl;
smthElse();
}
};
the application looks like this
int main()
{
A instanceA;
B instanceB;
instanceA.doSmth();
instanceB.doSmth();
getchar();
return 0;
}
And the output therefore is X=1 for both instances A and B. I was wondering why that is.
A uses base (X=1) and B uses deriv (X=2). deriv overloads X and B overloads K. Is this because the function smthElse() is only defined in A, thus A can't know about the existance of the overloaded variable K?
If so, is there a way for the function smthElse() to use the overloaded variable K?
I found the using keyword but also adding a using A::smthElse; in B won't change the behaviour of X not being printed as 2. The only way I can achieve this is by copying the function smthElse() from A and insert it into B.
Is there a different way to achieve what I'm looking for? Since it seems like an overkill to copy'n'paste the same function into B just to use an overridden variable.
Thanks in advance!
instanceB has two variables named K, A::K and B::K. However, the base class, A, only knows about one K, A::K.
That explains the output.
If so, is there a way for the function smthElse() to use the overloaded variable K?
Yes, you can do that by adding a virtual function in A that returns a reference to base and adding a virtual function in base that returns a reference to i.
class base
{
public:
int& getX( return X;}
private:
int X = 1;
};
class deriv : public base
{
public:
int& getX( return X;}
private:
int X = 2;
};
class A
{
public:
base& getK() { return K; }
virtual void doSmth()
{
std::cout << "A" << std::endl;
smthElse();
}
virtual void smthElse()
{
std::cout << getK().getX() << std::endl;
// ^^^^^^^^^^^^^ use the virtual functions
}
public:
base K;
};
class B : public A
{
public:
deriv& getK(){ return K; }
void doSmth()
{
std::cout << "B" << std::endl;
smthElse();
}
public:
base K;
};
PS I hope this is just curiosity and you don't write production code with such style. You will end up confusing yourself and anybody who tries to understand your code.
When you write
virtual void smthElse()
{
std::cout << K.X << std::endl;
}
smthElse is virtual
K is not (a member variable could not be virtual: it has no meaning for an attribute).
In other terms, it means that B::smthElse will ovevrride A::smthElse but B::K and A::K are two distinct, unrelated and independent variables.
When smthElse is called in the context of a B, K still means A::K.
As a solution, you might create a virtual accessor to Ks:
class base { ...};
class deriv{ ...};
class A
{
base K;
public:
virtual const base& theK() { return K; }
virtual void smthElse() { std::cout << theK().X << "\n"; }
};
class B : public A
{
deriv K;
public:
virtual const base& theK() { return K; }
};
When B{}.smthElse() is called, it will call B::theK() which will return B::K (a deriv instance).

C++ overloading method based on derived class

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.

Array of pointers to member functions in base class

I need an array of pointers to member functions in a base class like this
class Base {
public:
typedef int(Base::*func)();
func f[3];
Base();
void run();
};
void Base::run()
{
cout << (this->*f[0])() << endl;
cout << (this->*f[1])() << endl;
cout << (this->*f[2])() << endl;
}
The function run() will be the same for all child classes. But pointers in the array f[] will refer to member functions that will be defined in the child classes.
class Child: public Base {
public:
typedef int(Child::*func)();
func f[3];
int A();
int B();
int C();
Child();
};
int Child::A()
{
return 1;
}
int Child::B()
{
return 2;
}
int Child::C()
{
return 3;
}
Child::Child()
{
f[0] = &Child::A;
f[1] = &Child::B;
f[2] = &Child::C;
}
If I run this code in program I get problems
Child x;
x.run();
How to do this?
This works:
class Base {
public:
typedef int(Base::*func)();
func f[3];
virtual int A() { return 0; }
virtual int B() { return 0; }
virtual int C() { return 0; }
Base() {};
void run()
{
cout << (this->*f[0])() << endl;
cout << (this->*f[1])() << endl;
cout << (this->*f[2])() << endl;
}
};
class Child: public Base {
public:
int A() { return 1; }
int B() { return 2; }
int C() { return 3; }
Child()
{
f[0] = &Base::A;
f[1] = &Base::B;
f[2] = &Base::C;
}
};
You're facing two major obstacles here.
One, you never initialize the Base::f but that is what run operates on. You declare a member f in the child class and initialize it in the constructor. The Base classes f is never initialized, and is filled with garbage. When you call run, it tries to use those random values. This is undefined behavior.
Two, int(Base::*)() and int(Child::*)() are two distinct and incompatible types. You look like you want to fill the array with pointers to child functions and call them from the base class.
There are a couple ways to fix this:
You could make run virtual and implement it in the child class to call the functions.
You could put the functions in the base class and make them virtual, so pointers to them will call the derived versions.
You could make an array of std::function objects instead of pointers.

C++ Manager object and virtual functions

I am trying to wrap my head around using a manager object to loop through the objects in an array and invoke the virtual functions for each object. Here is my code so far, thanks to some very helpful suggestions, it compiles but still doesn't make use of polymorphism the way that I want it to. Thanks in advance for any tips that can point me in the right direction.
#include <iostream>
class avian{
private:
static const int max_birds = 25;
avian* birds[max_birds];
int num_birds;
public:
avian() : num_birds(0){}
virtual ~avian() {
for (int i = 0; i < num_birds; ++i) { delete birds[i]; }
}
bool add(avian* b){
if (num_birds >= max_birds){ return false; }
birds[num_birds++] = b;
return true;
}
void make_bird(){
for (int i = 0; i< num_birds; ++i){birds[i]->make_bird();
}
}
virtual void lay_eggs(){} ;
virtual void bird_noise(){} ;
};
class turkey : public avian{
public:
void lay_eggs() const{ std::cout << "000\n"; }
void bird_noise() const { std::cout << "Gobble Gobble Gobble!\n"; }
};
class chicken : public avian {
public:
void lay_eggs() const { std::cout << "OOOOO\n"; }
void bird_noise() const { std::cout << "Bock Bock Bock!\n"; }
};
class quail : public avian{
public:
void lay_eggs() const { std::cout << "ooooooooo\n"; }
void bird_noise() const { std::cout << "Chirr Chirr Chirr!\n"; }
};
int main(){
avian* my_turkey = new turkey;
my_turkey->make_bird();
my_turkey->lay_eggs();
my_turkey->bird_noise();
delete my_turkey;
return 0;
}
You don't have a virtual base class destructor:
virtual ~avian() { ... }
Calls to delete pointer_to_avian will will call avian::~avian, but they will not propagate to the destructors of derived classes - UB, as compiler says.
avian::lay_eggs is declared, but not defined. Did you mean to make it pure virtual function? You've overriden it in every derived class.
avian::bird_noise - same as above
You forgot to delete my_turkey in main - you're leaking memory.
Your base virtual methods are not marked as const. But methods in derived classes are const. So they are not overriden.
Rule of thumb is to use override keyword in order to avoid such errors

How to re-type pointer to a class and be able to reach classes functions based on it's type?

I'm writing a C++ code which should populate a screen (and it's behaviour) based on a function from the object pointer was initiated with. Let's better show it on a code:
class A:parentClass {
public:
int X () {return 5;}
}
class B:parentClass {
public:
int X () {return 3;}
}
class C:parentClass {
public:
int X () {return 1;}
}
main {
parentClass *p;
p = new A;
printf("%d\n,p.x); //to return 5
delete p;
p = new B;
printf("%d\n,p.x); //to return 3
}
I'm getting something like this on compilation:
‘class parrentClass’ has no member named ‘x’
I know that this is wrong, as parrentClass simply doesn't have that member, but I don't have an idea how to solve this. I tried to go through templates, but I'm not getting anywhere.
I also tried to replace "parentClass *p;" with "int *p;", but then I'm getting:
cannot convert ‘CardsFrame*’ to ‘int*’
Thanks for your suggestions in advance,
Jan
You need to declare the X() method virtual on the parent class for this to work:
class ParentClass
{
public:
virtual int X();
};
To be clear: the following is a complete working example (compiled with gcc):
#include <iostream>
class ParentClass {
public:
virtual int x() = 0;
};
class A : public ParentClass {
public:
int x() { return 5; }
};
class B : public ParentClass {
public:
int x() { return 3; }
};
class C : public ParentClass {
public:
int x() { return 1; }
};
int main() {
ParentClass *p;
p = new A;
std::cout << p->x() << std::endl; // prints 5
delete p;
p = new B;
std::cout << p->x() << std::endl; // prints 3
delete p;
}
You really need to get your basics right as your syntax is all wrong. You need to use p->X() to call the function. And to answer the actual question make X() virtual in the base class.
printf("%d\n,p.x); //to return 5
should be:
printf("%d\n,p->X()); //to return 5
Also, X() should be virtual in the Base class.