Array of pointers to member functions in base class - c++

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.

Related

I couldn't find reason behind garbage values here in this code

#include<iostream>
using namespace std;
class Base {
private: int b;
protected: int a;
public: int c; void setdata(); int getdata(); };
void Base ::setdata() { int a = 10; int b = 20; int c = 30; }
int Base::getdata() { return b; }
class Derived: public Base { public: void display() { setdata(); cout << a << endl << getdata() << endl << c << endl; } };
int main() { Derived xyz; xyz.display(); return 0; }
Lets look at your setdata function:
void Base ::setdata() { int a = 10; int b = 20; int c = 30; }
Inside it you define three new variables a, b and c, which are totally unrelated with the Base member variables of the same name.
That means the Base member variables will be uninitialized and with indeterminate values. And printing them leads to undefined behavior.
Your setdata function should set the Base member variables, which are already declared and defined and can be used as-is:
void Base ::setdata() { a = 10; b = 20; c = 30; }
With that said, a better solution is to use a constructor to initialize the member variables instead of a separate function:
class Base
{
public:
Base()
: a{ 10 }, b{ 20 }, c{ 30 } // An initializer list, to initialize members
{
// Empty body of constructor function
}
// Rest of class, without the setdata function ...
};

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.

Copied object changes attributes from the base class pointer it used to copy

Consider the following classes:
class Base {
public:
... // include virtual destructor and rest of methods
virtual void changeField(int val) = 0;
virtual Base * clone() const = 0;
};
class Derived: public Base {
int x;
public:
... // include its destructor and rest of its methods
void changeField(int val) { x = val; }
Derived * clone() const { return new Derived(*this); }
};
Suppose I have an existing Base * pointer bp that points to an Derived object. Then I call bp->clone() to make a copy and store the pointer of the resulting object in a Base * pointer, copyPointer.
When I try to changeField on the copyPointer, the value is changed, but the original object has its field also changed. Why is this? And what can I do to prevent this? Would I have to create an entirely new object from scratch?
Edit: Here is my main function in which I implement the described scenario
int main() {
try {
Base * copyPointer = bp->clone();
copyPointer->changeField(5);
cout << copyPointer->print() << endl; //prints the field of Derived
delete copyPointer;
}
catch (exception& e) { // I also have an Exception class in my code
cout << e.what() << endl;
}
}
Your assumption, that the function changeField() on the copyPointer changes the original object, is wrong!
I elaborated your example:
#include <iostream>
using std::cout;
using std::endl;
class Base {
public:
// include virtual destructor and rest of methods
virtual void changeField(int val) = 0;
virtual Base * clone() const = 0;
virtual int print() const =0;
};
class Derived: public Base {
int x;
public:
// include its destructor and rest of its methods
Derived(int i):x(i) {}
void changeField(int val) { x = val; }
Derived * clone() const { return new Derived(*this); }
int print()const { return x; }
};
int main() {
Base* bp =new Derived(3);
cout <<bp->print() <<endl;
Base * copyPointer = bp->clone();
copyPointer->changeField(5);
cout <<copyPointer->print() <<endl; //prints the field of Derived
cout <<bp->print() <<endl;
}
and the output is:
3
5
3

c++ double pointer polymorphism

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.