I have a parent class which as a member contains an array of pointers to objects of the same type as itself. I have another class that derives from the parent class. I want that the derived class uses an array of pointers to objects of its own (not the parent class). The deriving class calls methods on those objects that are stored in the array of pointers; it calls both methods which are defined and implemented in the derived class as well as in the base class. The code below obviously doesn't compile as parent contains no member z (in derived::doX()). I could dyanamic_cast(p[i]).z before accessing z, but I would have to do that on EVERY method in b at runtime.
If I hide "p" in the derived class (by casting the p's during object construction), I essentially get two arrays of pointers p, however, I want all methods operate on the same objects (residing in p). I tried templates but ran into a recursive issue. Any idea how to solve this?
#include <iostream>
#include <stdlib.h>
using namespace std;
class parent{
protected:
parent** p;
int num;
int x;
public:
parent(int _num, parent** _ps);
virtual void doX();
virtual void print();
};
class derived : public parent {
protected:
//derived** p;
int z;
public:
derived(int _num, parent** _ps) : parent(_num, _ps){};
virtual void doX();
virtual void print();
};
void parent::doX(){
for(int i=0;i<num;i++){
p[i]->x = 1;
}
}
void parent::print(){ cout << "x " << x << endl;
}
parent::parent(int _num, parent** _ds){
num=_num;
p = _ds;
}
void derived::doX(){
for(int i=0;i<num;i++){
p[i]->z = 2;
}
parent::doX();
}
void derived::print(){
cout << "x " << x << endl;
cout << "z " << z << endl;
}
int main(){
const int NUM = 2;
parent** ps = (parent**)malloc(sizeof(parent)*NUM);
for(int i=0; i< NUM; i++){
ps[i] = new derived(NUM, ps);
}
ps[0]->doX();
ps[0]->print();
ps[0]->print();
}
You are on the right track! You should use the "p" defined in the parent class. In the derived class setter methods you enforce that the derived type must be used (as the parameter type). For instance your constructor for defined will be:
derived(int _num, derived** _ps) : parent(_num, _ps){};
Then, when you're using p in the derived methods, you know that p is really a derived type, and you can safely cast it.
Related
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).
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
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.
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.
In c++ pass to a function/method a derived class, in the place of a base class and still have information about the derived class?.
Ex: Say that I have a base class: "geometry" and some other class: "shape" form where I derive "rectangle" and "circle".
double area::geometry( shape& object, int i )
{
if i = 1:
rectangle thisObject = object;
double side1 = thisObject.getheight();
double side2 = thisObject.getwidth();
if i = 2:
circle thisObject = object;
double side1 = thisObject.radius * thisObject.radius;
double side2 = 3.14;
return side1 * side2;
}
The problem is that you have to suppose that the "return side1 * side2", is a very complicated code that I don't want to repeat. So I prefer to set up the problem depending on the type of input to the function, than to overload it.
The idea is very similar to this one: Is it possible to pass derived classes by reference to a function taking base class as a parameter.
Thanks!
Edit: Tried to make the code clearer.
The usual approach would be to use polymorphism:
void func(const base& ob)
{
ob.doSomethingPolymorphic();
}
where doSomethingPolymorphic() is a virtual member function of base.
If func needs to know what type ob is when you pass it in, "you are doing it wrong". The WHOLE POINT of polymorphism is that all objects appear to be the same from an outside observer, but internally do different things. The typical example is animals:
#include <iostream>
using namespace std;
class Animal
{
public:
virtual void Say() = 0;
};
class Dog : public Animal
{
public:
void Say() { cout << "Woof Woof" << endl; }
};
class Pig : public Animal
{
public:
void Say() { cout << "All animals are equal, but pigs are "
"more equal than other animals" << endl; }
};
class Cat : public Animal
{
public:
void Say() { cout << "Meow, Meow" << endl; };
};
void AnimalTalk(Animal *a[], int size)
{
for(int i = 0; i < size; i++)
{
a[i]->Say();
}
}
int main()
{
Cat c;
Pig p;
Dog d;
Animal* list[3] = { &p, &c, &d };
AnimalTalk(list, 3);
}