Make a child class inherit specific attributes from two different parent classes? - c++

I have a problem with a Diamond inheritance exercise.
I have one base class A. Here is its constructor :
A::A(std::string name) : _hp(10), _ep(10), _ad(0)
{
std::cout << "A object created !" << std::endl;
return ;
}
Then, I have two parent classes B and C. Here are their constructors:
B::B(std::string name) : A(name)
{
std::cout << "B object created !" << std::endl;
this->_hp = 100;
this->_ep = 50;
this->_ad = 20;
return;
}
C::C(std::string name) : A(name)
{
std::cout << "C object created !" << std::endl;
this->_hp = 100;
this->_ep = 100;
this->_ad = 30;
return ;
}
And finally, I have one child class . Here is its constructor:
D::D(std::string name) : A(name + "_comes_from_A")
{
this->_name = name;
std::cout << "D object created !" << std::endl;
this->_hp = C::_hp;
this->_ep = B::_ep;
this->_ad = C::_ad;
return;
}
The D class inherits from class B and C.
The B and C classes both inherits from class A. I did something like this :
class A
{
// code here
protected:
std::string _name;
int _hp;
int _ep;
int _ad;
};
class B : virtual public A
{
// code here
};
class C : virtual public A
{
// code here
};
class D : public B, public C
{
// code here
};
As it can be noticed in the constructor of D class, I want it to inherits _ep from the B class (50) and _hp and _ad from the C class (100 and 30).
However, if I check the value of the _ep value in my D class, (with something like this for instance) :
std::cout << "ENERGY POINTS " << this->_ep << std::endl;
it is always equal to 100 (which comes from the C class).
I have noticed it depends on the order in which I handle inheritance for D class but I would like to be able to access values of any of the parent class from my child class. Can someone help me with that ? Thanks in advance!
MINIMAL REPRODUCIBLE EXAMPLE :
class A
{
public :
A(){
return ;
};
A(std::string name) : _hp(10), _ep(10), _ad(0){
std::cout << "A object created !" << std::endl;
return ;
};
~A(){
std::cout << "A object " << this->_name << " destroyed." << std::endl;
return ;
};
protected:
std::string _name;
int _hp;
int _ep;
int _ad;
};
class B : virtual public A
{
public :
B(){
return ;
};
B(std::string name) : A(name){
std::cout << "B object created !" << std::endl;
this->_hp = 100;
this->_ep = 50;
this->_ad = 20;
return ;
};
~B(){
std::cout << "B object " << this->_name << " destroyed." << std::endl;
return ;
};
};
class C : virtual public A
{
public :
C(){
return ;
};
C(std::string name) : A(name){
std::cout << "C object created !" << std::endl;
this->_hp = 100;
this->_ep = 100;
this->_ad = 30;
return ;
};
~C(){
std::cout << "C object " << this->_name << " destroyed." << std::endl;
return ;
};
};
class D : public B, public C
{
public :
D(){
return ;
};
D(std::string name) : A(name + "_comes_from_a"){
this->_name = name;
std::cout << "D object created !" << std::endl;
this->_hp = C::_hp;
this->_ep = B::_ep;
this->_ad = C::_ad;
std::cout << "HIT POINTS " << this->_hp << std::endl;
std::cout << "ENERGY POINTS " << this->_ep << std::endl;
std::cout << "ATTACK DAMAGE " << this->_ad << std::endl;
return;
}
~D(){
std::cout << "D object " << this->_name << " destroyed." << std::endl;
return ;
};
};
int main(void)
{
D obj_D("TEST");
return (0);
}

Okay, I got my program to work properly. Maybe I didn't explain well what I wanted to do, but I'm posting my solution here.
There are 4 classes A, B, C and D. They all have _hp, _ep and _ad variables.
D inherits from B AND C, which in turn inherit from A.
         A
       /     \
      B     C
       \      /
          D
I wanted my D class to take :
_ep value from the B class
_hp and _ad values from the C class
Here is the minimal reproducible example of the code that worked for me :
# include <iostream>
# include <string>
class A
{
public :
A(){
return ;
};
A(std::string name) : _hp(10), _ep(10), _ad(0){
std::cout << "A object created !" << std::endl;
return ;
};
~A(){
std::cout << "A object " << this->_name << " destroyed." << std::endl;
return ;
};
protected:
std::string _name;
int _hp;
int _ep;
int _ad;
};
class B : virtual public A
{
public :
B(){
return ;
};
B(std::string name) : A(name){
std::cout << "B object created !" << std::endl;
this->_hp = 100;
this->_ep = 50;
this->_ad = 20;
return ;
};
~B(){
std::cout << "B object " << this->_name << " destroyed." << std::endl;
return ;
};
static const int EP = 50;
};
class C : virtual public A
{
public :
C(){
return ;
};
C(std::string name) : A(name){
std::cout << "C object created !" << std::endl;
this->_hp = 100;
this->_ep = 100;
this->_ad = 30;
return ;
};
~C(){
std::cout << "C object " << this->_name << " destroyed." << std::endl;
return ;
};
static const int HP = 100;
static const int AD = 30;
};
class D : public B, public C
{
public :
D(){
return ;
};
D(std::string name) : A(name + "_comes_from_a"){
this->_name = name;
std::cout << "D object created !" << std::endl;
this->_hp = C::HP;
this->_ep = B::EP;
this->_ad = C::AD;
std::cout << "HIT POINTS " << this->_hp << std::endl;
std::cout << "ENERGY POINTS " << this->_ep << std::endl;
std::cout << "ATTACK DAMAGE " << this->_ad << std::endl;
return;
}
~D(){
std::cout << "D object " << this->_name << " destroyed." << std::endl;
return ;
};
};
int main(void)
{
D obj_D("TEST");
return (0);
}
The difference with the example that I posted in the question is that I declared static const int variables (HP, EP and AD) in my B and C classes. Thus, I am now able to access the values either from B or C classes in the constructor of class D. Typically, what I did earlier was wrong :
// before (not working)
this->_hp = C::_hp;
this->_ep = B::_ep;
this->_ad = C::_ad;
// now (working)
this->_hp = C::HP;
this->_ep = B::EP;
this->_ad = C::AD;
The output is now :
A object created !
D object created !
HIT POINTS 100
ENERGY POINTS 50
ATTACK DAMAGE 30
D object TEST destroyed.
C object TEST destroyed.
B object TEST destroyed.
A object TEST destroyed.

Related

Static Cast to CRTP Interface [duplicate]

This question already has answers here:
What is object slicing?
(18 answers)
Closed 1 year ago.
I am building up a CRTP interface and noticed some undefined behavior. So, I built up some sample code to narrow down the problem.
#include <iostream>
template <typename T>
class Base {
public:
int a() const { return static_cast<T const&>(*this).a_IMPL(); }
int b() const { return static_cast<T const&>(*this).b_IMPL(); }
int c() const { return static_cast<T const&>(*this).c_IMPL(); }
};
class A : public Base<A> {
public:
A(int a, int b, int c) : _a(a), _b(b), _c(c) {}
int a_IMPL() const { return _a; }
int b_IMPL() const { return _b; }
int c_IMPL() const { return _c; }
private:
int _a;
int _b;
int _c;
};
template <typename T>
void foo(const T& v) {
std::cout << "foo()" << std::endl;
std::cout << "a() = " << static_cast<Base<T>>(v).a() << std::endl;
std::cout << "b() = " << static_cast<Base<T>>(v).b() << std::endl;
std::cout << "c() = " << static_cast<Base<T>>(v).c() << std::endl;
}
int main() {
A v(10, 20, 30);
std::cout << "a() = " << v.a() << std::endl;
std::cout << "b() = " << v.b() << std::endl;
std::cout << "c() = " << v.c() << std::endl;
foo(v);
return 0;
}
The output of this code is:
a() = 10
b() = 20
c() = 30
foo()
a() = 134217855
b() = 0
c() = -917692416
It appears that there is some problem when casting the child class, which implements the CRTP "interface", to the interface itself. This doesn't make sense to me because the class A plainly inherits from Base so, shouldn't I be able to cast an instance of A into Base?
Thanks!
You copy and slice when you cast to Base<T>.
Cast to a const Base<T>& instead:
std::cout << "a() = " << static_cast<const Base<T>&>(v).a() << std::endl;
std::cout << "b() = " << static_cast<const Base<T>&>(v).b() << std::endl;
std::cout << "c() = " << static_cast<const Base<T>&>(v).c() << std::endl;
It turns out I was casting incorrectly to a value rather than a reference
std::cout << "a() = " << static_cast<Base<T>>(v).a() << std::endl;
should become
std::cout << "a() = " << static_cast<const Base<T>&>(v).a() << std::endl;

how does c++ compiler handle "this" pointer in virtual function

i got a confuse about how does c++ compiler handle "this" pointer in virtual function, my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
using namespace std;
class A {
public:
void print_A(void) {
cout << "A::THIS = " << this << endl;
return;
}
int a;
virtual ~A(void) {
return;
}
};
class B {
public:
virtual void print(void) {
cout << "B::THIS = " << this << endl;
return;
}
int b;
};
class C: public A, public B {
public:
void print(void) {
cout << "C::THIS = " << this << endl;
return;
}
int c;
};
class D {
public:
int d;
virtual ~D(void) {
return;
}
};
class E: public D, public C {
public:
int e;
virtual ~E(void) {
return;
}
};
void global_print(B *pb) {
cout << "pb = " << pb << endl;
pb->print();
return;
}
int main(int argc, char *argv[]) {
E e;
A *pa = &e;
B *pb = &e;
C *pc = &e;
D *pd = &e;
E *pe = &e;
cout << "pa = " << pa << endl;
cout << "pb = " << pb << endl;
cout << "pc = " << pc << endl;
cout << "pd = " << pd << endl;
cout << "pe = " << pe << endl;
pb->print();
pc->print();
pe->print();
global_print(&e);
return 0;
this is result compiled with g++ in my linux:
pa = 0x7ffc1e7c7a80
pb = 0x7ffc1e7c7a90
pc = 0x7ffc1e7c7a80
pd = 0x7ffc1e7c7a70
pe = 0x7ffc1e7c7a70
C::THIS = 0x7ffc1e7c7a80
C::THIS = 0x7ffc1e7c7a80
C::THIS = 0x7ffc1e7c7a80
pb = 0x7ffc1e7c7a90
C::THIS = 0x7ffc1e7c7a80
I can't understand that i send &e to global_print and pb in global_print is equal to 0x7ffc1e7c7a90. And then i invode pb->print(), the this pointer in global_print is 0x7ffc1e7c7a80 which is equel to pc. It seems that the pb->print() convert class B to class C, but class B is the father class of class C, how dose it convert?
And although pb can get addres of C::print by virtual function, it's only a address that havn't enough information to konw that is need to convert class B to class C, so how does the program konw that need to convert class B to class C in the run time?
THANKS a lot! wish have a nice day!

container of polymorphic objects - call (so to say static) function once per containing class

I have a virtual base class B and some deriving classes class D1, class D2, class D3.
I also have a container holding pointer to number of instances Container<B*> cont;
Now i have some different type of tasks:
things that need to be done for each object (thats the classic - no problems with that)
things that need to be done once for each kind of object (that also does not depend on the object itself)
To make it more imaginable a bit of code.
#include <iostream>
#include <vector>
class B{
public:
virtual void executeOncePerClass() = 0;
virtual void executeOncePerObject() = 0;
};
using Container = std::vector<B*>;
class D1 : public B
{
public:
D1(int i_i):i(i_i){}
void executeOncePerClass() override { executeOncePerClass_s(); };
void executeOncePerObject()override { std::cout << " D1 : " << i << " member " << std::endl;};
private:
int i = 0;
static void executeOncePerClass_s(){ std::cout << " D1 static" << std::endl; };
};
class D2 : public B
{
/* same as D1 */
public:
D2(int i_i):i(i_i){}
void executeOncePerClass() override { executeOncePerClass_s(); };
void executeOncePerObject()override { std::cout << " D2 : " << i << " member " << std::endl;};
private:
int i = 0;
static void executeOncePerClass_s(){ std::cout << " D2 static" << std::endl; };
};
class D3 : public B
{
public:
D3(float i_i):i(i_i){}
void executeOncePerClass() override { executeOncePerClass_s(); };
void executeOncePerObject()override { std::cout << " D3 : " << i << " member " << std::endl;};
private:
float i = 0;
static void executeOncePerClass_s(){ std::cout << " D3 static" << std::endl; };
};
int main(){
D1 d1_1(1); D1 d1_2(2); D1 d1_3(3);
D2 d2_1(23);
D3 d3_1(1); D3 d3_2(2); D3 d3_3(3);
Container cont{
&d3_2, &d1_1, &d3_3, /* &d2_1 */ &d3_1, &d1_3, &d1_2
};
std::cout << " foreach class " << std::endl;
for(auto c : cont){
/* ??? */
}
std::cout << " foreach instance: " << std::endl;
for(auto c : cont){
c->executeOncePerObject();
}
}
Is there some easy code to get this done?
Maybe storing the executeOncePerClass functions address (this would also capture the if D4 inherits from D3 without overriding)?
At best without a lot of dynamic memory or associative container?
One Sidequestion: is there a better mechanism for this polymorphic static function thingy?

why inherited functions changes the member variables in base class not the one of the same name of object called it

I want to ask why the setX function here sets the x member variable in class A not the member variable x in class D even though I call setX function through D object?
How does the compiler did that ?
#include<iostream>
using namespace std;
class A
{
public:
int x;
A() { cout << "A cons" << endl; }
void setX(int i){ x = i; cout << "setxA" << endl; }
void print() { cout << x; }
};
class B : public A
{
public:
int x =30;
B() { cout << "B cons" << endl; }
};
class D : public B {
public:
D() {
cout << "D cons" << endl;
}
void func() {
setX(10);
cout << x << endl;
cout << B::x << endl;
cout << A::x << endl;
}
};
int main()
{
D d;
d.func();
return 0;
}
the output from this code is
30
30
10
This is called name hiding. Both A and B have a member x and both members always exist (you just cannot access them the same way). A knows about his member x and so the setX function sets exactly this member A::x. In B, you define another x which hides A::x. This means that if you do
B obj;
obj.x = 10;
or
D obj;
obj.x = 10;
you will access B::x both of the times (because B is lower in the inheritance hierarchy and therefore hides A::x).
Here is an example of how you can still access A::x using different casts.
#include <iostream>
struct A {
int x = 0;
void setX(int i) { x = i; }
};
struct B : A {
int x = 20;
};
int main()
{
B obj;
A castToA = static_cast<A>(obj);
A* castToAPtr = reinterpret_cast<A*>(&obj);
std::cout
<< "access via B: " << obj.x << "\n"
<< "access via A: " << castToA.x << "\n"
<< "access via A*: " << castToAPtr->x << "\n"
<< "access via B::(A::x): " << obj.A::x << "\n\n";
obj.setX(100);
std::cout << "set x to 100\n\n";
std::cout
<< "access via B: " << obj.x << "\n"
<< "access via A: " << castToA.x << "\n"
<< "access via A*: " << castToAPtr->x << "\n"
<< "access via B::(A::x): " << obj.A::x << "\n\n";
return 0;
}
which yields the output:
access via B: 20
access via A: 0
access via A*: 0
access via B::A::x: 0
set x to 100
access via B: 20
access via A: 0
access via A*: 100
access via B::A::x: 100
Your class B has an x and also A has an X. As this, you have two x in B!
So you may remove the x from your B class?
If you need both, you can access them with
A::x or B::x inside a method of B which you already did.
So your D class have also both x and calling setX calls the setX method of A. As in D you see the x from B which hides your x from A everything works as expected.
Your method A::setX did not know that you derive later from it. If you want to override the method, B has define a own B::setX which will then also be used in D.
Example how to override a method and access the parameter in derived class:
class A
{
public:
int x; // A::x
int y = 40; // A::y
// this function only knows about A::x
void setX(int i){ x = i; cout << "setxA" << endl; }
void setY(int i){ y = i; cout << "setyA" << endl; }
};
class B : public A
{
public:
int x =30; // this x ( B::x) hide A::x
int y =50; // this y hides also A::y
// now we override setY from A ( hiding setY from A! )
void setY(int i){ y = i; cout << "setyB" << endl; }
};
class D : public B {
public:
void func() {
setX(10); // Calls A::setX, as A::setX only knows about
// A::x it will access A::x
cout << "X" << std::endl;
cout << x << endl;
cout << B::x << endl;
cout << A::x << endl;
setY(90);
cout << "Y" << std::endl;
cout << y << endl;
cout << B::y << endl;
cout << A::y << endl;
}
};
int main()
{
D d;
d.func();
return 0;
}

C++ sample Observer Template Class error

I am creating observer template sample in C++ on windows.
Here there is an agent which has a list of customers. Whenever an entity(variable x) of the agent changes it notifies its customers about the same and passes the value of x to customers. The customers then store this value in their respective variables.
In the below code the agent acts as subject and the customers act as observers.
The agents are created from their agent template class and the customers are created from their customer template class.
template <typename T>
class customer // acts as base observer class
{
char name[50];
public:
customer()
{
cout << __FUNCTION__ "(): " << "DEFAULT CONS\n";
}
customer(char* nm)
{
strcpy_s(name, nm);
cout << __FUNCTION__ "(): " << "name set to " << name << "\n";
}
char * getName()
{
return(name);
}
virtual void update(int c)
{
}
};
class customerC: public customer<customerC>
{
int c;
public:
customerC()
{
cout << __FUNCTION__ "(): " << "DEFAULT customerc cons\n";
}
customerC(char* nm):customer<customerC>(nm)
{
cout << __FUNCTION__ "(): " << "customer is " << getName() << "\n";
}
void update(int val)
{
cout << __FUNCTION__ "(): c to " << c << "\n";
c = val;
}
};
class customerD: public customer<customerD>
{
int d;
public:
customerD()
{
cout << __FUNCTION__ "(): " << "DEFAULT customerd cons\n";
}
customerD(char* nm):customer<customerD>(nm)
{
cout << __FUNCTION__ "(): " << "customer is " << getName() << "\n";
}
void update(int val)
{
cout << __FUNCTION__ "(): c to " << d << "\n";
d = val;
}
};
template<typename T>
class agent
{
char name[50];
int x;
protected:
vector<customer<T>*> custList;
public:
agent()
{
cout << __FUNCTION__ "(): " << "DEFAULT agent cons\n";
}
virtual void setx(int c)
{
cout << __FUNCTION__ "(): " << "Setting x to " << c << "\n";
//// x = c;
//// notifyObs();
}
virtual void getx()
{
cout << __FUNCTION__ "(): " << "x = " << x << "\n";
}
void addCust(customer<T>* cobj)
{
cout << __FUNCTION__ "(): " << "Adding customer " << cobj->getName() << " to list.\n";
custList.push_back(cobj);
}
void showCust()
{
cout << __FUNCTION__ "(): " << "Customers are:\n";
if(custList.empty())
cout << "\n\nYou have no items.";
else
{
vector<customer<T>*>::iterator cs;
for(cs = custList.begin(); cs != custList.end(); ++cs)
{
cout << (*cs)->getName() << "\n";
}
}
}
int notifyObs()
{
cout << __FUNCTION__ "(): " << "Customers notified are:\n";
if(custList.empty())
cout << "\n\nYou have no items.";
else
{
vector<customer<T>*>::iterator cs;
for(cs = custList.begin(); cs != custList.end(); ++cs)
{
cout << (*cs)->getName() << "\n";
(*cs)->update(x);
}
}
return 0;
}
};
class agentS: public agent<agentS>
{
int x;
public:
agentS()
{
cout << __FUNCTION__ "(): " << "DEFAULT agentS cons\n";
}
void setx(int c)
{
cout << __FUNCTION__ "(): " << "Setting x to " << c << "\n";
x = c;
notifyObs();
}
void getx()
{
cout << __FUNCTION__ "(): " << "x = " << x << "\n";
}
};
int _tmain(int argc, _TCHAR* argv[])
{
customerC cobj("c1");
customerD dobj("c2");
agentS agS;
agS.addCust(cobj);
//// agS.addCust<customer<customerC>>(cobj);
//// agS.addCust(dobj);
agS.showCust();
agS.setx(4);
return(0);
}
I get compilation error
error C2664: 'agent<T>::addCust' : cannot convert parameter 1 from 'customerC' to 'customer<T> *'
I know the way I have called addCust is wrong but still not getting any idea as to call it.
Any hint to resolve this issue?
Also is the way I have created agents class correct?
class agentS: public agent<agentS>
When I call addCust() function I pass observer objects.
By creating your agentS class that way, the effective signature for addCust becomes void addCust(customer<agentS>* cobj);. However, your customer classes are not templated on the agent type (there doesn't actually seem to be a reason for it to be templated).
You appear to be mixing dynamic polymorphism (inheritance and virtual functions with customer) and static polymorphism (templates to create a vector of one type of customer). Either of these options on their own would make more sense:
Dynamic polymorphism (inheritance). You can store different types of customer in the same container, by storing the base class pointer, and use the customer base class and virtual functions to tread them in the same way:
struct customer {};
struct customerC : customer {};
struct customerD : customer {};
struct agent
{
void addCust(customer* customer) { ... }
std::vector<customer*> custList;
};
int main()
{
agent a;
customerC c;
a.addCust(&c);
}
Static polymorphism (templates). The agent class is templated on the customer type, so the vector can only contain one type of customer, but it's easy to create a specific agent for any given customer type:
struct customer {};
struct customerC : customer {};
struct customerD : customer {};
template<CustomerT>
struct agent
{
void addCust(CustomerT* customer) { ... }
std::vector<CustomerT*> custList;
};
int main()
{
agent<customerC> a;
customerC c;
a.addCust(&c);
}