I have a pair of base/derived classes which are almost identical, but not quite.
I could simply copy all the code of Base1 > Derived1 to create Base2 > Derived2, but that would be ugly, and would require making almost any modification twice.
Question: How can I share as much code as possible between the two pairs, to avoid code duplication?
I tried to create a small toy example that has most features of the actual problem. I want to avoid having duplicate code for the identical part of the interface of D1 and D2. If you want to see more of the actual problem, scroll to the end of the question.
#include <iostream>
using namespace std;
//////////// 1st PAIR ////////////
class B1 {
protected:
string name;
public:
B1() : name("B1") { } // constructors are different between B1 and B2
void speak() { cout << name << endl; } // identical between B1 and B2
};
template<typename T>
class D1 : public B1 {
T x; // identical between D1 and D2
public:
D1(const T &a) { x = a + name.size(); } // refers to base class member
int getX() { return x; } // identical between D1 and D2
int nameLength() { return name.size(); } // accesses member of B, identical between D1 and D2
// differences between D1 and D2 follow:
int add(int i, int j) { return i+j; } // different signature between D1 and D2
void more() {} // not present in D1
};
//////////// 2nd PAIR ////////////
class B2 {
protected:
string name;
public:
B2() : name("B2") { }
void speak() { cout << name << endl; }
};
template<typename T>
class D2 : public B2 {
T x; // identical between D1 and D2
public:
D2(const T &a) { x = a + name.size(); }
int getX() { return x; } // identical between D1 and D2
int nameLength() { return name.size(); } // accesses member of B, identical between D1 and D2
int add(int i, int j, int k) { return i+j+k; } // different signature between D1 and D2
};
// this is just to test that the program compiles and works
int main() {
D1<int> d1(5);
D2<long> d2(6l);
cout << d1.getX();
cout << d1.nameLength();
return 0;
}
The interface of B1 and B2 can be shared by making them inherit from a class BInterface.
It was suggested to me to use multiple inheritance to be able to do the same with D1 and D2, through an additional base class DInterface. Furthermore, it was suggested I try to use the curiously recurring template pattern to allow this additional base class to access the members of D1 and D2. My attempt at doing this follows. I find it a bit complicated, and I would like to know if this is a reasonable approach, and whether there is a better way to do the same.
#include <iostream>
using namespace std;
//////////// COMMON INTERFACES ////////////
class BInterface {
protected:
string name;
BInterface(const string &n) : name(n) { }
public:
void speak() { cout << name << endl; }
};
template<typename D>
class DInterface {
private:
D &derived() { return *static_cast<D *>(this); }
protected:
DInterface() {}
public:
int getX() { return derived().x; }
int nameLength() { return derived().name.size(); }
};
//////////// 1st PAIR ////////////
class B1 : public BInterface {
public:
B1() : BInterface("B1") { } // constructors are different between B1 and B2
};
template<typename T>
class D1 : public B1, public DInterface< D1<T> > {
friend class DInterface< D1<T> >;
T x; // identical between D1 and D2
public:
D1(const T &a) { x = a + name.size(); } // refers to base class member
int add(int i, int j) { return i+j; } // different signature between D1 and D2
void more() {} // not present in D1
};
//////////// 2nd PAIR ////////////
class B2 : public BInterface {
public:
B2() : BInterface("B2") { }
};
template<typename T>
class D2 : public B2, public DInterface< D2<T> > {
friend class DInterface< D2<T> >;
T x; // identical between D1 and D2
public:
D2(const T &a) { x = a + name.size(); }
int add(int i, int j, int k) { return i+j+k; } // different signature between D1 and D2
};
// this is just to test that the program compiles and works
int main() {
D1<int> d1(5);
D2<long> d2(6l);
cout << d1.getX();
cout << d1.nameLength();
return 0;
}
Since several people have commented that this is too broad, and that the context from my actual problem is lost, below I will describe the actual problem:
Mathematica has a C extension API. Certain data types, such as dense or sparse arrays or images can be manipulated in C. I am working on a much easier to use C++ interface. The system also includes in interface generator: a lot of glue code is automatically generated based on a symbolic representation of a C++ class interface in Mathematica. Here's an older version of the system.
I am now working on handling images. Mathematica has Image and Image3D, distinct expressions for 2D and 3D images. Image can also have different pixel types, such as byte, 16-bit, floating point, etc.
The C API uses a single representation for all of these, including 2D and 3D images, called MImage (a pointer type, multiple MImages may point to the same image in memory).
It is convenient for have separate classes for 2D and 3D images in C++, and also to template these on the pixel type. These correspond to the D1 and D2 classes above. However, in some cases, it is useful to operate with "generic" images that may have any pixel type (pixels can't be accessed in this case, but we can do other things with the images too). This is why I also have the base classes B1 and B2.
Here's the implementation of 2D image references so far (this is not done and it will change). I still need to add 3D images, which will share a lot of code.
This solution factors out the concepts of having a name and having a value through a base class that has a name.
If the individual components of the derived classes do not depend on each other then this kind of inheritance composition is relatively easy to maintain.
If the concerns of the base classes are interdependent then you'll have to use CRTP and marshal calls via the derived class.
#include <iostream>
using namespace std;
// factor out common parts
struct NamedThing
{
NamedThing(std::string &&name) : name(std::move(name)) {}
NamedThing(std::string const& name) : name(name) {}
void speak() { cout << name << endl; }
std::size_t nameLength() const { return name.size(); }
private:
std::string name;
};
template<class T, class Base>
struct NamedValue : public Base
{
T x; // identical between D1 and D2
public:
NamedValue(T const& v)
: Base()
, x(this->nameLength())
{}
T getX() { return x; } // identical between D1 and D2
};
//////////// 1st PAIR ////////////
class B1 : public NamedThing
{
public:
B1() : NamedThing("B1") { } // constructors are different between B1 and B2
};
template<typename T>
class D1 : public NamedValue<T, B1> {
using inherited = NamedValue<T, B1>;
public:
D1(const T &a)
: inherited(a)
{
}
// differences between D1 and D2 follow:
int add(int i, int j) { return i+j; } // different signature between D1 and D2
void more() {} // not present in D1
};
//////////// 2nd PAIR ////////////
class B2 : public NamedThing
{
public:
B2() : NamedThing("B2") { }
};
template<typename T>
class D2 : public NamedValue<T, B2> {
using inherited = NamedValue<T, B2>;
public:
D2(const T &a)
: inherited(a)
{
}
int add(int i, int j, int k) { return i+j+k; } // different signature between D1 and D2
};
// this is just to test that the program compiles and works
int main() {
D1<int> d1(5);
D2<long> d2(6l);
cout << d1.getX();
cout << d1.nameLength();
return 0;
}
Where you want to inherit for code reuse you can use private inheritance. With private inheritance the derived classes are blocked from being cast to their base classes.
#include <string>
#include <iostream>
class super
{
std::string name_;
public:
super( std::string n ): name_(n) {}
virtual ~super(){}
std::string name() const { return this->name_; }
void name( std::string n ) { this->name_ = n; }
};
class base1: private super
{
int vertices_;
public:
base1( std::string n, int v ): super( n ), vertices_( v ) {}
virtual ~base1() {}
using super::name; // make both name methods accessible
int vertices() const { return this->vertices_; }
void vertices( int v ) { this->vertices_ = v; }
};
class base2: private super
{
std::string surname_;
public:
base2( std::string n, std::string s ): super( n ), surname_( s ) {}
virtual ~base2() {}
// to make only one name method accessible
std::string name() const { return this->super::name(); }
std::string surname() const { return this->surname_; }
};
// class derived1: public base1 { ... };
// class derived2: public base2 { ... };
int main()
{
base1 v1( "triangle", 3 );
base2 v2( "john", "doe" );
std::cout << "base1: " << v1.name() << " " << v1.vertices() << "\n";
std::cout << "base2: " << v2.name() << " " << v2.surname() << "\n";
v1.name( "square" );
v1.vertices( 4 );
std::cout << "base1: " << v1.name() << " " << v1.vertices() << "\n";
//v2.name( "jane" ); // illegal code
//super *p1 = &v1; // illegal code
//super *p2 = &v2; // illegal code
//derived1 d1(...);
//derived2 d2(...);
//base1 *p1 = &d1; // allowed
//base2 *p2 = &d2; // allowed
//derived1 *p1 = dynamic_cast< derived1* >((super*)&d2); // Not allowed
return 0;
}
With private inheritance you cannot directly access any base class methods outside the derived class. You have two options to allow this: (1) In base1 we use a public using statement to make the two name methods accessible. (2) In base2 we only want one of the name functions so we write a stub method that calls the super class method (NOTE: as this is inline it should result in the same assembly code as the using method).
Related
In multiple inheritance,where all the base class contains same function name with different functionality, we can access the protected function from particular base class using "::" scope resolution operator.
However, I tried something else. I created the objects of the base class in inside the child class. And tried calling the function using through object of that particular class.
But I was getting the following compiler error:
"‘void A::func(int&)’ is protected within this context."
Please let me know where did i go wrong.
#include <iostream>
using namespace std;
class A
{
protected:
void func(int & a)
{
a = a * 2;
}
};
class B
{
protected:
void func(int & a)
{
a = a * 3;
}
};
class C
{
protected:
void func(int & a)
{
a = a * 5;
}
};
class D : public A,public B,public C {
public:
int a;
A a_val;
B b_val;
C c_val;
void update_val(int new_val)
{
a = new_val;
a_val.func(a);
b_val.func(a);
c_val.func(a);
}
void check(int);
};
void D::check(int new_val)
{
update_val(new_val);
cout << "Value = " << a << endl;
};
int main()
{
D d;
int new_val;
cin >> new_val;
d.check(new_val);
}
If you want to keep your code with the base classes as having independent functionality and still remaining protected the easiest way to resolve your issue is by slightly changing the name of your protected functions and adding a public function that calls the protected members: See these class declarations for example:
class A {
public:
void func( int& a ) {
func_impl( a );
}
protected:
void func_impl( int& a ) {
a = a * 2;
}
};
class B {
public:
void func( int& b ) {
func_impl( b );
}
protected:
void func_impl( int& b ) {
b = b * 3;
}
};
class C {
public:
void func( int& c ) {
func_impl( c );
}
protected:
void func_impl( int& c ) {
c = c * 5;
}
};
class D : public A, public B, public C {
public:
int a;
A a_val;
B b_val;
C c_val;
void update_val( int val ) {
a = val;
a_val.func( a );
b_val.func( a );
c_val.func( a );
}
void check( int );
};
void D::check( int val ) {
update_val( val );
std::cout << "Value = " << a << std::endl;
}
This provides a nice public interface to call the protected member functions. This also resolves the issue of accessing the protected members. When I run your program and input a value of 5 it returns a result of 150 and works as expected.
This snippet should show you how inheritance works and when you can and can not access protected members:
class DerivedA : public Base {
public:
Base b;
void call_message() {
b.message(); // Protected Member of Base class can not be accessed
}
};
class DerivedB : public Base {
public:
void call_message() {
message(); // This works without problem!
}
};
Just as I did above one way to resolve this is by adding a public interface caller to the protected implementation.
class Base {
public:
void message() {
message_impl();
}
protected:
void message_impl() {
std::cout << "This is a protected member of Base\n";
}
};
Now you can do this:
class DerivedA {
public:
Base b;
void call_message() {
b.message(); // Accessible through public interface.
}
};
When you are in your derived class, it has access to its own ancestor methods. But it doesn't have access to your variables member protected and private methods and variables.
Redesign your code, you are trying things and contorting the other classes design for bad reasons. Francis' code is a good solution, but D doesn't need to inherit from anything.
If you don't want to create another function, you can do something like this:
#include <iostream>
using namespace std;
class A
{
protected:
void func(int & a)
{
a = a * 2;
}
};
class B
{
protected:
void func(int & a)
{
a = a * 3;
}
};
class C
{
protected:
void func(int & a)
{
a = a * 5;
}
};
class D : public A,public B,public C {
public:
int a;
void update_val(int new_val)
{
a = new_val;
this->A::func(a);
this->B::func(a);
this->C::func(a);
}
void check(int);
};
void D::check(int new_val)
{
update_val(new_val);
cout << "Value = " << a << endl;
};
int main()
{
D d;
int new_val;
cin >> new_val;
d.check(new_val);
}
This works because, this refers to the current instance of class D, and it already inherits class A, class B, class C. So you can directly access the protected functions of the respective classes.
Remember: It will not work if you have not inherited the classes.
Please consider the following piece of code:
#include <iostream>
#include <string>
enum Type { T1, T2 };
class Base {
public:
std::string baseName;
Type type;
Base(const std::string& bn, Type t):
baseName(bn), type(t) {}
};
class Derived1 : public Base
{
public:
std::string dName;
int x = 10;
Derived1(const std::string& bn, const std::string& dn):
Base(bn, Type::T1), dName("Dervied1"+dn) {}
int getX(void) const { return x; }
};
class Derived2 : public Base
{
public:
std::string dName;
int y = 20;
Derived2(const std::string& bn, const std::string& dn):
Base(bn, Type::T2), dName("Derived2"+dn){}
int getY(void) const { return y; }
};
void func(Base& b)
{
if (b.type == Type::T1)
{
Derived1& d1 = static_cast<Derived1&>(b);
std::cout << d1.baseName << " " << d1.dName << " " << d1.getX();
std::cout << std::endl;
}
else
{
Derived2& d2 = static_cast<Derived2&>(b);
std::cout << d2.baseName << " " << d2.dName << " " << d2.getY();
}
};
int main(void)
{
Derived1 d1("Base", "foo");
func(d1);
Derived2 d2("Base", "foo");
func(d2);
}
The requirement is to have a function that can take in the base class value and then depending on the "type" of the derived instance, do something different. My question is - is this the right way of doing things or am I missing some important design pattern. I remember reading that use of static_cast or dynamic_cast means that there is something inherently wrong with the design. I understand that ideally the base class can have virtual functions that the derived classes implement, and at run time they get polymorphically dispatched. However, in this case there are two functions in each derived class that are specific to those classes, viz. getX and getY. How can I change the design to make it better and perhaps not use the cast?
Thanks!
The requirement is to have a function that can take in the base class value and then depending on the "type" of the derived instance, do something different.
That is exactly what polymorphism is all about. But you are not using it the way it is meant to be used.
My question is - is this the right way of doing things
No.
am I missing some important design pattern.
This would be better handled by getting rid of Type altogether and introduce a virtual method in Base.
I understand that ideally the base class can have virtual functions that the derived classes implement, and at run time they get polymorphically dispatched.
Exactly.
However, in this case there are two functions in each derived class that are specific to those classes, viz. getX and getY.
So? Using polymorphism correctly does not prevent that.
How can I change the design to make it better and perhaps not use the cast?
Use polymorphism correctly. For example:
#include <iostream>
#include <string>
class Base
{
public:
std::string baseName;
Base(const std::string& bn):
baseName(bn) {}
virtual void doIt() = 0;
};
class Derived1 : public Base
{
public:
std::string dName;
int x = 10;
Derived1(const std::string& bn, const std::string& dn):
Base(bn), dName("Dervied1"+dn) {}
int getX(void) const { return x; }
void doIt() override
{
std::cout << baseName << " " << dName << " " << getX();
std::cout << std::endl;
}
};
class Derived2 : public Base
{
public:
std::string dName;
int y = 20;
Derived2(const std::string& bn, const std::string& dn):
Base(bn), dName("Derived2"+dn) {}
int getY(void) const { return y; }
void doIt() override
{
std::cout << baseName << " " << dName << " " << getY();
}
};
void func(Base& b)
{
b.doIt();
}
int main(void)
{
Derived1 d1("Base", "foo");
func(d1);
Derived2 d2("Base", "foo");
func(d2);
}
And then take it a step farther by moving common code around so it can be shared by the derived classes:
#include <iostream>
#include <string>
class Base
{
public:
std::string baseName;
Base(const std::string& bn):
baseName(bn) {}
virtual void doIt()
{
std::cout << baseName;
}
};
class Derived : public Base
{
public:
std::string dName;
Derived(const std::string& bn, const std::string& dn):
Base(bn), dName(dn) {}
void doIt() override
{
Base::doIt();
std::cout << " " << dName;
}
};
class Derived1 : public Derived
{
public:
int x = 10;
Derived1(const std::string& bn, const std::string& dn):
Derived(bn, "Dervied1"+dn) {}
int getX(void) const { return x; }
void doIt() override
{
Derived::doIt();
std::cout << " " << getX();
std::cout << std::endl;
}
};
class Derived2 : public Derived
{
public:
int y = 20;
Derived2(const std::string& bn, const std::string& dn):
Derived(bn, "Derived2"+dn) {}
int getY(void) const { return y; }
void doIt() override
{
Derived::doIt();
std::cout << " " << getY();
}
};
void func(Base& b)
{
b.doIt();
}
int main(void)
{
Derived1 d1("Base", "foo");
func(d1);
Derived2 d2("Base", "foo");
func(d2);
}
If you have the option of using a virtual member function, as outlined by the other answer, it is the best approach to use. However, there are situations where you don't have that luxury. In that case, you can build your dispatch mechanism based on the type of the derived type.
#include <iostream>
#include <string>
#include <map>
class Base {
public:
std::string baseName;
Base(const std::string& bn): baseName(bn) {}
virtual ~Base() {}
// Don't store type ID per instance.
// Make it a virtual function so derived classes
// can return the same value for each instance.
virtual int getTypeID() = 0;
// Helper function for derived classes to use so each
// derived class can have a unique type id associated
// with it. This eliminates the need for having an enum.
static int getNextTypeID();
{
static int typeID = 0;
return ++typeID;
}
};
class Derived1 : public Base
{
public:
std::string dName;
int x = 10;
Derived1(const std::string& bn,
const std::string& dn):
Base(bn), dName("Dervied1"+dn) {}
// get type ID for this class.
// Every instance of the class will return
// same value.
virtual int getTypeID()
{
return getTypeIDStatic();
}
// This is a crucial piece of function
// that allows type based dispatch mechanism to work.
static int getTypeIDStatic()
{
static int typeID = Base::getNextTypeID();
return typeID;
}
int getX(void) const { return x; }
};
class Derived2 : public Base
{
public:
std::string dName;
int y = 20;
Derived2(const std::string& bn,
const std::string& dn):
Base(bn), dName("Derived2"+dn){}
int getY(void) const { return y; }
virtual int getTypeID()
{
return getTypeIDStatic();
}
static int getTypeIDStatic()
{
static int typeID = Base::getNextTypeID();
return typeID;
}
};
// Define a function type.
using Function = void (*)(Base& b);
// Keep a registry of functions that can be called for
// different types derived from Base.
std::map<int, Function>& getRegisteredFunctionsMap()
{
static std::map<int, Function> functionsMap;
return functionsMap;
}
// Provide a mechanism to register functions for types
// derived from Base.
template <typename T>
void registerFunction(Function f)
{
getRegisteredFunctionsMap()[T::getTypeIDStatic()] = f;
}
void func(Base& b)
{
// Check whether there is a function base on the type of b.
std::map<int, Function>& functionsMap = getRegisteredFunctionsMap();
std::map<int, Function>::iterator iter = functionsMap.find(b.getTypeID());
if ( iter != functionsMap.end() )
{
// If yes, call it.
iter->second(b);
}
else
{
// No function to deal with the type.
// Deal with the situation.
}
};
// A function that can be called when the real type is Derived1.
void derived1Fun(Base& b)
{
// Assume that b is derived.
Derived1& d1 = dynamic_cast<Derived1&>(b);
// Now use d1.
std::cout << d1.baseName << " " << d1.dName << " " << d1.getX();
std::cout << std::endl;
}
// A function that can be called when the real type is Derived2.
void derived2Fun(Base& b)
{
// Assume that b is Derived2.
Derived2& d2 = dynamic_cast<Derived2&>(b);
// Now use d2.
std::cout << d2.baseName << " " << d2.dName << " " << d2.getY();
std::cout << std::endl;
}
int main(void)
{
// Register functions for Derived1 and Derived2.
registerFunction<Derived1>(derived1Fun);
registerFunction<Derived2>(derived2Fun);
// Make the function calls.
Derived1 d1("Base", "foo");
func(d1);
Derived2 d2("Base", "foo");
func(d2);
}
Output of running the above program:
Base Dervied1foo 10
Base Derived2foo 20
Big edit:
I have a code in which I have to add a constant member in a inherited class by using _elemente (which is a vector). Not to add a member in the inherited classes, just by using _elemente. In every inherited classes (let's say B, C, D and E) I withh have MAX_VAL1, MAX_VAL2 and so on with different values.
I tried:
#include <iostream>
#include <iomanip>
#include <vector>
typedef unsigned int Uint;
typedef vector<Uint> TVint;
typedef vector<Uint>::const_iterator TIterator;
class A
{
protected:
Uint _count;
TVint _elemente;
public:
//
};
class B : public A
{
const int MAX_VAL;
};
But it has a member and I don't have to have a member in the inherited class.
All the code here:
.h: http://pastebin.com/P3TZhWaV
.cpp: http://pastebin.com/ydwy2L5a
The work from the inherited classes is done using that constant members.
if MAX_VAL1 < count
{
throw Exception() {}
}
if (_elemente.size() == 0) // As _elemente is a vector from STL
{
_elemente.push_back(0);
}
for (int i = _elemente.size(); i < count; i++)
{
_elemente.push_back(_elemente[i * (i+1) / 2]);
}
}
I don't think that is correct as I have to use the Vector from STL and I don't really think that is the way the constant member from a inherited class without the actual member declared should be added.
Thanks for your help.
You could use a virtual function, something like this:
class A
{
virtual int max_val() const = 0;
protected:
Uint _count;
TVint _elemente;
public:
//
};
class B : public A
{
int max_val() const { return 42; }
};
if ( max_val() < _count ) ...
Based on other comments it seems like you want a const number that is accessible in the base class which can have a different value depending on the derived class. You could achieve that like this: https://ideone.com/JC7z1P
output:
A: 50
B: 80
#include <iostream>
using namespace std;
class Base
{
private:
const int aNumber;
public:
// CTOR
Base( const int _aNumber ) :
aNumber( _aNumber ) {}
// check value
int getNumber() const
{
return aNumber;
}
};
class A : public Base
{
public:
A() : Base( 50 ) {}
};
class B : public Base
{
public:
B() : Base( 80 ) {}
};
int main() {
A a;
B b;
std::cout << "A: " << a.getNumber() << std::endl;
std::cout << "B: " << b.getNumber() << std::endl;
return 0;
}
When you write like
class B : public A
{
const int MAX_VAL;
};
what value do you expect B's class instance to hold with current approach?
Have you tried to add ctor to B (to initialize MAX_VAL to some exact value), so that whole class definition should be like
class B : public A
{
const int MAX_VAL;
public:
B(int max_val):MAX_VAL(max_val) {}
};
Also, the code above shows a lot of unanswered questions. Some of them:
Do you really need it to be member? mark it as 'static' (static const int MAX_VAL = 5) . That would mean, every B's instance MAX_VAL would be equal
All of type redifinitions don't look meaningful. What if you use intrisic types and auto?
Usually one doesn't compare size() with 0 - just calls empty().
Have you tried to read Stroustrup or Lippman?
If you want to access it statically, you can do it by using templates :
ABase gives polymorphic access to value
A gives static access to value
B and Care examples of usage
.
// This is the polymorphic root class
class ABase
{
public:
ABase(int maxV) : _maxV(maxV) {}
int maxValue() { return _maxV; }
private:
int _maxV;
};
// This class gives static method
template<int V_MaxValue>
class A : public ABase
{
public:
A() : ABase(V_MaxValue) {}
static int maxValue() { return V_MaxValue; }
};
class B : public A<42>
{
};
class C : public A<35>
{
};
// Static access (neex explicit class call) :
// B::maxValue() => 42
// C::maxValue() => 35
//
// Polymorphic call :
// ABase* poly = new B();
// poly->maxValue() => 42
My question concerns the combination of public and private inheritance as a tool to separate interface and implementation in a C++ class. In this pattern, the interface base class declares the common functions (class Base0). The common implementation is carried out in a class derived virtually from the interface base (class Impl0 : virtual public Base0). This class contains any common data members. The extension classes are written in two steps. First the extended interface is defined by virtual inheritance from the interface base (class Base1 : virtual public Base0). Second, the extended implementation is carried out by deriving publicly from Base1 (for interface) and privately from Impl0 (for implementation): class Impl1 : public virtual Base1, private Impl0. My questions are the following:
(1) if the functions in the extension class define functions that require common data in Impl0, do I have to replicate that data in `Impl1'?
(2) Is there any way to avoid this replication?
As a minimal example, consider a class hierarchy for implementing the four basic arithmetic functions: add(), substr(), mult() and div(). The basic version, MathOps, contains the add() and subtr() functions. The extended version, MathOps_Extn, contains mult() and div(). The above technique gives the following class hierarchy.
#include<iostream>
using std::cout;
using std::endl;
class MathOps {
public:
virtual int add(int x) = 0;
virtual int subtr(int x) = 0;
};
class MathOps_Impl : public virtual MathOps {
private:
int m_y;
public:
MathOps_Impl(int y) : m_y(y) {
cout << "MathOps_Impl initialized with value: " << m_y << endl;
}
virtual int add(int x) { return x + m_y;}
virtual int subtr (int x) { return m_y - x;}
};
class MathOps_Extn : public virtual MathOps {
// Extends MathOps by adding mult() and div()
public:
virtual int mult(int x) = 0;
virtual int div(int x) = 0;
};
class MathOps_Extn_Impl : public virtual MathOps_Extn, private MathOps_Impl {
private:
int m_y; // Have to replicate member data m_y here.
public:
MathOps_Extn_Impl(int y) : MathOps_Impl(y), m_y(y) {
cout << "MathOps_Extn_Impl initialized with value: " << m_y << endl;
}
virtual int mult(int x) {
return x * m_y;
}
virtual int div(int x) {
int quotient = x == 0? 0 : m_y/x;
return quotient;
}
};
int main() {
MathOps_Extn* B = new MathOps_Extn_Impl(10);
cout << "add 20: " << B->add(20) << endl;
cout << "subtr 20: " << B->subtr(20) << endl;
cout << "mult 2: " << B->mult(2) << endl;
cout << "div 5: " << B->div(5) << endl;
Note the replication of m_y in MathOps_Extn_Impl. Is there any way to avoid this replication?
Note the replication of m_y in MathOps_Extn_Impl. Is there any way to
avoid this replication?
Yes. Give MathOps_Impl::m_y protected access instead of private.
You're explicitly asking why derived classes can't access private data. That's by design.
You can give access to the common data, without breaking encapsulation, via protected member functions in the common implementation class.
Gratuitous example follows :)
#include <cstdio>
class Math
{
public:
virtual ~Math() {}
virtual int add(int b) const = 0;
};
class MoreMath : public virtual Math
{
public:
virtual ~MoreMath() {}
virtual int subtract(int b) const = 0;
};
class MathImpl : public virtual Math
{
private:
int m_a;
public:
MathImpl(int a) : m_a(a) {}
virtual ~MathImpl() {}
int add(int b) const { return m_a + b; }
protected:
int value() const { return m_a; }
};
class MoreMathImpl : public virtual MoreMath, private MathImpl
{
public:
MoreMathImpl(int a) : MathImpl(a) {}
int subtract(int b) const { return value() - b; }
};
int main()
{
MoreMath* one = new MoreMathImpl(1);
printf("1 + 2 = %d\n", one->add(2));
printf("1 - 2 = %d\n", one->subtract(2));
delete one;
return 0;
}
I try to understand how double dispatch works. I created an example where a monster and a warrior derived from the abstract class Creature could fight. The class Creature has method "fight", which is defined in derived classes, and in each derived class is defined what happens if warrior fights with warrior or with monster etc. I wrote the following code:
#include<iostream>
using namespace std;
class Monster;
class Warrior;
class Creature{
public:
virtual void fight(Creature&) =0;
};
class Monster: public Creature{
void fightwho(Warrior& w) {cout<<"Monster versus Warrior"<<endl; }
void fightwho(Monster& m) {cout<<"Monster versus Monster"<<endl; }
public:
void fight(Creature& c) {c.fightwho(*this);}
};
class Warrior: public Creature{
void fightwho(Warrior& w) {cout<<"Warrior versus Warrior"<<endl; }
void fightwho(Monster& m) {cout<<"Monster versus Warrior"<<endl; }
public:
void fight(Creature& c) {c.fightwho(*this);}
};
int main()
{
Warrior w;
Monster m;
w.fight(m);
}
This results in compiler error, which I foresee:
ex12_10.cpp: In member function ‘virtual void Monster::fight(Creature&)’: ex12_10.cpp:17:30: error: ‘class Creature’ has no member named ‘fightwho’
ex12_10.cpp: In member function ‘virtual void Warrior::fight(Creature&)’: ex12_10.cpp:24:29: error: ‘class Creature’ has no member named ‘fightwho’
But I don't know how to proceed from here... Please help.
Well, obviously, you really don't have fightwho declared in your Creature class, so you need to declare it there, and declare it as virtual.
Double dispatch works in a way that for call (this assumes Warrior& w = ..., not Warrior w):
w.fight(m);
First the virtual mechanism will chose Warrior::fight instead of Monster::fight and then the overloading mechanism will pick Monster::fightwho(Warrior& m) instead of Warrior::fightwho(Warrior& m). Note that it would make more sense if you would have:
Warrior w;
Monster m;
Creature& c1 = w;
Creature& c2 = m;
c1.fight(c2); // not w.fight(m)
Therefore, the method which will eventually be called will be dispatched according to type of the object on which you call it and type of the object sent as argument, i.e. double dispatch
Additionally, please note that this might not be the best example as your types are members of the same hierarchy. Visitor design pattern is a good example of double dispatch implementations in languages which don't support it as first class citizens (i.e. C++ and derivatives: Java, C#...)
As #CrazyCasta correctly notes, when your class hierarchy starts to grow, this approach becomes much harder to maintain and can result in explosion of number of methods, so choose carefully...
My contribution to above answers is providing well-tested example in order to clarify double dispatch concept in reality. If you review the below code you will find the answer of how can I implement by myself.
#include <iostream>
using namespace std;
class A;
class A1;
class A2;
class B1;
class B2;
class B {
public:
// dispatcher function to A
virtual void collide(const A& a) const = 0;
// actual collision logic B with types of A
virtual void collide(const A1& a) const = 0;
virtual void collide(const A2& a) const = 0;
};
class A {
public:
// dispatcher function to B
virtual void collide(const B& b) const = 0;
// actual collision logic A with types of B
virtual void collide(const B1& b) const = 0;
virtual void collide(const B2& b) const = 0;
};
class A1 : public A {
public:
void collide(const B& b) const {
// dispatch to b
b.collide(*this);
}
void collide(const B1& b) const {
cout << "collision with B1 and A1" << endl;
}
void collide(const B2& b) const {
cout << "collision with B2 and A1" << endl;
}
};
class A2 : public A {
public:
void collide(const B& b) const {
// dispatch to a
b.collide(*this);
}
void collide(const B1& b) const {
cout << "collision with B1 and A2" << endl;
}
void collide(const B2& b) const {
cout << "collision with B2 and A2" << endl;
}
};
class B1 : public B {
public:
void collide(const A& b) const {
b.collide(*this);
}
void collide(const A1& b) const {
cout << "collision with A1 Bnd B1" << endl;
}
void collide(const A2& b) const {
cout << "collision with A2 Bnd B1" << endl;
}
};
class B2 : public B {
public:
void collide(const A& a) const {
a.collide(*this);
}
void collide(const A1& a) const {
cout << "collision with A1 Bnd B2" << endl;
}
void collide(const A2& a) const {
cout << "collision with A2 Bnd B2" << endl;
}
};
int main() {
A* a = new A1();
B* b = new B2();
// first dispatch is done by polymorphism ( a is resolved as a A1 )
// second dispatch is done in collide function by the function overloading
// ( in collide function we are sending A1 to collide function of B )
a->collide(*b);
}
Consider using a templated function to determine the type of the second object (RTTI) so that most code duplicating can be avoided, like this:
#include <iostream>
#include <vector>
struct Unit // abstract Unit superclass
{
virtual void interact(Unit *u2)=0;
};
template<typename U1,typename U2>
void interact(U1 u1,U2 u2);
struct UnitA : public Unit
{
void interact(Unit *u2) { ::interact(this, u2); }
};
struct UnitB : public Unit
{
void interact(Unit *u2) { ::interact(this, u2); }
};
int main()
{
std::vector<Unit*> units={new UnitA(), new UnitB(), new UnitA(), new UnitB()}; // all the units
// make each pair of units interact with eachother once
for (int i1=0; i1<units.size(); i1++)
for (int i2=i1+1; i2<units.size(); i2++)
units[i1]->interact( units[i2] );
}
template<typename U1,typename U2>
void interact(U1 u1,U2 u2) // takes care of the RTTI work
{
if (auto dc=dynamic_cast<UnitA*>(u2)) interact(*u1, *dc);
else if (auto dc=dynamic_cast<UnitB*>(u2)) interact(*u1, *dc);
else { std::cerr<< "Unkown subclass\n"; exit(1); }
}
// now we can handle the interaction for each subclass permutation:
void interact(UnitA& u1,UnitA& u2) { std::cout<<"UnitA-UnitA\n"; }
void interact(UnitA& u1,UnitB& u2) { std::cout<<"UnitA-UnitB\n"; }
void interact(UnitB& u1,UnitA& u2) { std::cout<<"UnitB-UnitA\n"; }
void interact(UnitB& u1,UnitB& u2) { std::cout<<"UnitB-UnitB\n"; }
The output is a print for the interaction between each pair of units in the vector:
UnitA-UnitB
UnitA-UnitA
UnitA-UnitB
UnitB-UnitA
UnitB-UnitB
UnitA-UnitB
However, this approach is slow because of run-time type checks and because a vector of pointers results in poor caching. For high-performance games consider a more "data oriented design".
If you want to do this you will need to use RTTI. You will need to check the type of the thing being passed in. In general this is not the best design pattern to be used if you can avoid it. If you want to interact two objects you generally want to use the standard interface of another. For instance you might say creature.attack(other_creature) and attack might query the defense of the other creature, and based on that and it's own stats post an hp update to the other_creature.