I'm working with some production code, some of which I cannot safely modify (without breaking things). My issue is that it I would like to use a specific method, one of the parameters of which is a pointer to a class. However the class as the parameter does not do what I want it to.
So I wrote a sub-class of that class and am attempting to call the above function, but it still uses the parent class' methods.
I have a MWE below:
#include <iostream>
class Parent
{
public:
Parent() {};
void method() {std::cout<<"in Parent\n";}
};
class Child : public Parent
{
public:
Child() {};
void method() {std::cout<<"in Child\n";}
};
void secondMethod(Parent* Pptr)
{
Pptr->method();
}
int main()
{
Child c = Child();
Parent* parentPtr = &c;
c.method();
parentPtr->method();
secondMethod(parentPtr);
secondMethod(&c);
return 0;
}
In the above example running this the output is of course:
in Child
in Parent
in Parent
in Parent
I believe the issue is slicing? Basically I'm casting to the pointer of the parent class, so it is considered as a Parent.
I have seen some ways around this by making methods virtual in the parent class but I don't have that option.
Is there some way to make secondMethod actual use the child's method? Specifically without changing the Parent class OR the secondMethod.
No not really if you aren't able to change the parent class or 'secondMethod'. The constructor of 'secondMethod' defines its parameter as Parent*. Passing a Child* to 'secondMethod' will cause the Child* to be upcast to Parent* and in turn will cause Parent's implementation of 'method' to be called.
If you can not change method to virtual function, you may can import template to solve your problem.
template<typename T>
void secondMethod(T* Pptr)
{
Pptr->method();
}
it may can work!!!
Related
So i have the following code:
#include <iostream>
using namespace std;
class Parent
{
int x;
public:
Parent(){x=10;}
void f(){cout<<x;}
};
class Child: public Parent
{
int x;
public:
Child(){x=20;}
void f(){cout<<x;}
};
int main()
{
Parent *pp;
Child c;
pp=&c;
pp->f();
return 0;
}
As you can see, i have two classes, Parent class and Child class publicly inherited from Parent class, so i wanted to see what can i do with pointer to a parent class.
I thought that it would be possible to use pointer to the parent class and use it on a child object, as i did in main, however, whenever i run this code, it prints out 10, which is the value i have for parent class variable x, considering that i made pp to point to child object, shouldn't it call the function f() defined in the child class and therefore, it should print the value of 20. What am i missing here? Any help appreciated!
The method f has to be virtual. As a start read this reference maybe helps.
#include <iostream>
using namespace std;
class Parent
{
int x;
public:
Parent(){x=10;}
virtual void f(){cout<<x;}
// ^^^^^^^ see this
};
class Child: public Parent
{
int x;
public:
Child(){x=20;}
virtual void f(){cout<<x;}
// ^^^^^^^ and this
// or since C++11 with override:
// void f() override {cout<<x;}
};
int main()
{
Parent *pp;
Child c;
pp=&c;
pp->f();
return 0;
}
Demo
There are at least two problems in the code.
First, the function f() must be declared virtual at least in the Parent class (with C++11 and later it is then good practice to append the keyword override in the Child class). The function being virtual is the mechanism that makes it possible to call the Child implementation via a Parent pointer.
Second, the variable x is declared both in the Parent and the Child class. This means that the Child object has two variables called x and by default x in Child functions will refer to the x declared in the Child class (the copy in the Parent class must be public or protected to be accessible from Child and must then, because of the name overlap, be referred to via a Parent type pointer or by explicitly specifying the class as in Parent::x).
I have code similar to the following:
template<class BASE_TYPE = COdbcQuery>
class CRemoteQuery : public BASE_TYPE
{
CRemoteDatabase m_Db;
public:
CRemoteQuery()
: BASE_TYPE(&m_Db)
{
}
~CRemoteQuery()
{
}
};
My problem is that m_Db.Open() must be called before passing m_Db to the base constructor.
If I call a method as an argument to the base constructor that calls Open(), it fails because m_Db has not yet been initialized.
I tried creating a virtual method in the base class, which would be called during initialization and this class could override, but template classes cannot override virtual methods.
Restructuring my base classes so that m_Db doesn't need to be opened first raises a lot of difficult issues. Is there no way to do this?
This sequence of events can be easily implemented by making a small design change:
class CRemoteDB {
protected:
CRemoteDatabase m_Db;
CRemoteDB()
{
m_Db.open();
}
};
template<class BASE_TYPE = COdbcQuery>
class CRemoteQuery : private CRemoteDB, public BASE_TYPE
{
public:
CRemoteQuery()
: BASE_TYPE(&m_Db)
{
}
~CRemoteQuery()
{
}
};
Parent classes always get constructed in declaration order. The CRemoteDB parent class gets constructed first, and CRemoteDatabase::open() gets called in the parent class's constructor.
Then BASE_TYPE gets constructed, and gets a pointer to the opened m_Db.
CRemoteQuery can access m_Db from its parent class no differently than it would be if it was its own class member.
but template classes cannot override virtual methods.
P.S. Whoever told you that was wrong. Template classes can certainly override virtual methods. I've got a massive hierarchy of templates here, all overriding virtual methods of their parent classes, left and right.
I am studying inheritance and polymorphism in C++ and I came across this example:
class Parent
{
public:
void a()
{
std::cout << "parentA";
}
virtual void b()
{
std::cout<<"parentB";
}
};
class Child : public Parent
{
public:
void b()
{
std::cout<<"childB";
}
};
Then in main:
int main()
{
Parent i= Child();
i.b(); //why doesn't this give parentB?
Parent *j= new Child();
j->b();
}
The outputs are parentA and childB respectively but I can't understand why. (isn't b() overriding?)
The first case should give parentB, since the object i has type Parent, not Child. The Child object is sliced - that is, its Parent subobject is copied to create i of type Parent, then the temporary Child is destroyed. You can often prevent confusing behaviour like this by making base classes abstract (that is, giving them pure virtual functions), so that they can't be instantiated.
The second case should give childB, since the object that j points to has dynamic type Child.
You have "sliced" the Child class into the Parent class. In order to access virtual methods, you need to store the instance polymorphically, like you have with your second example. Polymorphic variables are pointers and references.
Say we have two classes:
class Parent
{
public:
vector<int> x;
protected:
void Method();
}
and
class Child : public Parent
{
public:
vector<double> x;
}
and the method Method() operates on x and makes some operation, which is compatible for both types int and double:
void Parent::Method()
{
x.push_back(1);
}
Then, if I will create an instance of Child class, initialize vector<double> x, and then call derived method Method() from the base class, C++ will try to operate on Parent's member x and not the Child's one. Is there any way how to make base class method to automatically operate on the member that belongs to created class, Child's vector<int> x?
EDIT:
As McAden correctly noted, this behavior can be easily achieved using polymorphism: three classes - 1 base and 2 derived. But does it mean that it is impossible with just 2 classes?
Since you only want to create instances of Child and you want the Child to dictate the type of the vector, this problem is more naturally solved with a template Parent. As a simple example, Parent could be parameterized by what vector<> should contain:
template <typename T>
class Parent {
public:
std::vector<T> x;
protected:
void Method () { x.push_back(1); }
};
class Child : public Parent<double> {
//...
};
If you actually have many such things you want the child to control in the Parent, then you probably should treat Child more like a traits class for the Parent. Thus, Parent would actually be parameterized by its Child, and your code would then be using CRTP. which provides "static polymorphism".
template <typename CHILD>
class Parent {
protected:
void Method () {
CHILD *child = static_cast<CHILD *>(this);
child->x.push_back(1);
}
};
class Child : public Parent<Child> {
public:
std::vector<double> x;
};
Changing data types in dealing with inheritance isn't so much possible with the exception being cases where covariance is used. If you want to make a class that handles differing data types what you're probably looking for is a template class:
http://www.learncpp.com/cpp-tutorial/143-template-classes/
#include<stdio.h>
class parent
{
public:
parent()
{
}
};
class child : public parent
{
public:
child()
{
}
};
class master
{
public:
void view(parent a)
{
printf("view parent instances");
}
void view(child b)
{
printf("view child instances");
}
};
int main()
{
parent *ptr;
master mymaster;
ptr = new child;
mymaster.view(*ptr);
return 0;
}
output : "view parent instances"
I create a pointer from parent class. then I declared that pointer as child type. when i run mymaster.view(*ptr); , this always go to first view function (void view(parent a)), how to make it go to (void view(child b)). thankyou
With a little refactoring and a slightly different approach, you could use virtual functions. This enables the function from derived classes to be used when called using a pointer like below.
#include<stdio.h>
class parent
{
public:
parent()
{
}
virtual void view()
{
printf("View parent");
}
};
class child : public parent
{
public:
child()
{
}
virtual void view()
{
printf("View child");
}
};
class master
{
public:
void view(parent *a)
{
a->view();
}
};
int main()
{
parent *ptr;
master mymaster;
ptr = new child;
mymaster.view(ptr);
return 0;
}
This will output "View child". The same code without the virtual keywords will output "View parent". Note that the keyword only needs to be in the parent class, but is often used in the derived classes too for clarity.
The Wikipedia article on virtual functions explains the situation pretty well:
Virtual functions are resolved 'late'. If the function in question is
'virtual' in the base class, the most-derived class's implementation
of the function is called according to the actual type of the object
referred to, regardless of the declared type of the pointer or
reference. If it is not 'virtual', the method is resolved 'early' and
the function called is selected according to the declared type of the
pointer or reference.
Since the actual type of the object here is a child, the virtual function makes sure that the child's functionality is called even though the pointer is of parent type.
The type of *(parent*) is parent, so the method that gets called is view(parent). If you want to invoke view(child), you need to cast the pointer to a child* before passing it in, however...
You're using OOP backwards. You don't define multiple methods that know how to consume each specific type of sub-class, you define one method that can respect the contract provided by the parent class, and the sub-classes do their own thing internally.
ptr is a pointer to a parent object.
If you want to have the view(child) function called, you need to pass a child object to the function call.
Alternatively, you can cast it to a child pointer
mymaster.view(*(child*)ptr);
but you're likely to end up with all kinds of other problems.
The compiler decides the matching method according to the best choice.
The compiler sees that the variable is of type parent, so it calls the matching method.