I have a state machine sort of thing encapsulated in a class. This is done by calling a sequence of member functions in turn to do the actions. I also have several derived classes, and I want to do the same sequence on them. Is there a way I can template this code?
#include <iostream>
class MyClass {
std::string name;
public:
typedef void (MyClass::*Function)(std::ostream &ostr);
void Func1(std::ostream &ostr) { ostr << "F1" << name << std::endl; };
void Func2(std::ostream &ostr) { ostr << "F2" << std::endl; };
static Function printers[];
void Print(std::ostream &ostr);
};
MyClass::Function MyClass::printers[] = {
&MyClass::Func1,
&MyClass::Func2,
NULL
};
void MyClass::Print(std::ostream &ostr)
{
// various stuff to do before
// ...
int i = 0;
for (Function *fp = printers; *fp; fp++, i++) {
std::cerr << "Calling function " << i << std::endl;
((this)->*(*fp))(ostr);
std::cerr << "Called function " << i << std::endl;
}
// other stuff here...
}
class DerClass: public MyClass {
int index;
public:
typedef void (DerClass::*Function)(std::ostream &ostr);
void Func3(std::ostream &ostr) { ostr << "F3" << index << std::endl; };
static Function printers[];
void Print(std::ostream &ostr);
};
DerClass::Function DerClass::printers[] = {
&DerClass::Func1,
&DerClass::Func3,
NULL
};
// I'd rather not repeat all this stuff, can I template it??
void DerClass::Print(std::ostream &ostr)
{
// various stuff to do before
// ...
int i = 0;
for (Function *fp = printers; *fp; fp++, i++) {
std::cerr << "Calling function " << i << std::endl;
((this)->*(*fp))(ostr);
std::cerr << "Called function " << i << std::endl;
}
// other stuff here...
}
int main()
{
MyClass cl1;
cl1.Print(std::cout);
DerClass cl2;
cl2.Print(std::cout);
}
The code runs, and works, but I'd like to write the Print routine just once, rather than for each new class, is there a way to do that, templates? Other classes?
I was hoping for something like
template <class T>
void T::Print(std::ostream &str) {
int i = 0;
for (Function *fp = printers; *fp; fp++, i++) {
std::cerr << "Calling function " << i << std::endl;
((this)->*(*fp))(ostr);
std::cerr << "Called function " << i << std::endl;
}
}
That doesn't compile though.
error: invalid use of template type parameter âTâ void
T::Print(std::ostream &str) {
I would rather write this as a comment, but the amount of code wouldn't be readable at all.
Below you can find a possible solution on how to "inherit" your Print.
This should only be taken as suggestion or hint. Especially the initialization of the printers is not really done in "a good way".
Hope it helps you nonetheless
#include <iostream>
#include <string>
template <class Derived>
class MyClass {
std::string name;
protected:
typedef void (Derived::*Function)(std::ostream &ostr);
Function* printers;
public:
MyClass()
:printers(nullptr)
{
}
~MyClass()
{
delete[] printers;
}
virtual void initPrinters()
{
if (printers == nullptr)
{
printers = new Function[3];
printers[0] = &MyClass<Derived>::Func1;
printers[1] = &MyClass<Derived>::Func2;
printers[2] = NULL;
}
}
void destroyPrinters()
{
if (printers != nullptr)
{
delete[] printers;
}
}
void Print(std::ostream &ostr)
{
initPrinters();
// various stuff to do before
// ...
int i = 0;
for (Function *fp = printers; *fp; fp++, i++) {
std::cerr << "Calling function " << i << std::endl;
(((Derived*)this)->*(*fp))(ostr);
std::cerr << "Called function " << i << std::endl;
}
// other stuff here...
}
void Func1(std::ostream &ostr) { ostr << "F1" << name << std::endl; };
void Func2(std::ostream &ostr) { ostr << "F2" << std::endl; };
};
template <>
class MyClass<void> : public MyClass<MyClass<void>>
{
};
class DerClass : public MyClass<DerClass> {
int index;
public:
virtual void initPrinters() override
{
if (printers == nullptr)
{
printers = new Function[3];
printers[0] = &DerClass::Func1;
printers[1] = &DerClass::Func3;
printers[2] = NULL;
}
}
void Func3(std::ostream &ostr) { ostr << "F3" << index << std::endl; };
};
int main()
{
MyClass<void> cl1;
cl1.Print(std::cout);
DerClass cl2;
cl2.Print(std::cout);
}
EDIT: Second Approach
This one is prettier in my opinion. Also it is less code and it can be optimized by the compiler:
#include <iostream>
#include <string>
class MyClass {
std::string name;
protected:
template <class T>
void print(std::ostream &ostr, void(T::*printFunc)(std::ostream&))
{
(((T*)this)->*printFunc)(ostr);
}
template <class T, typename... PrintFunctions>
void print(std::ostream &ostr, void(T::*printFunc)(std::ostream&), PrintFunctions... printFuncs)
{
(((T*)this)->*printFunc)(ostr);
print(ostr, printFuncs...);
}
public:
virtual void Print(std::ostream &ostr)
{
print(ostr, &MyClass::Func1, &MyClass::Func2);
}
void Func1(std::ostream &ostr) { ostr << "F1" << name << std::endl; };
void Func2(std::ostream &ostr) { ostr << "F2" << std::endl; };
};
class DerClass : public MyClass {
int index;
public:
virtual void Print(std::ostream &ostr) override
{
print(ostr, &DerClass::Func1, &DerClass::Func3);
}
void Func3(std::ostream &ostr) { ostr << "F3" << index << std::endl; };
};
int main()
{
MyClass cl1;
cl1.Print(std::cout);
DerClass cl2;
cl2.Print(std::cout);
}
If "various stuff" and "other stuff" are different, you can make those parts virtual.
But you can't call a member function of a subclass in the base class, the functions all need to have the same type.
One suggestion might be to indirect through free functions.
class MyClass;
typedef void (*Printer)(MyClass*, std::ostream&);
class MyClass {
std::string name;
public:
MyClass();
void Func1(std::ostream &ostr) { ostr << "F1" << name << std::endl; };
void Func2(std::ostream &ostr) { ostr << "F2" << std::endl; };
void Print(std::ostream &ostr);
protected:
MyClass(Printer* ps) : myprinters(ps) {}
virtual void PrePrint() { /* Various stuff... */ }
virtual void PostPrint() { /* Other stuff... */ }
private:
Printer* myprinters;
};
void MyFunc1(MyClass* obj, std::ostream& os) { obj->Func1(os); }
void MyFunc2(MyClass* obj, std::ostream& os) { obj->Func2(os); }
Printer myclassprinters[] = {
&MyFunc1,
&MyFunc2,
NULL
};
MyClass::MyClass()
: myprinters(myclassprinters)
{
}
void MyClass::Print(std::ostream &ostr)
{
PrePrint();
int i = 0;
for (Printer *fp = myprinters; *fp; fp++, i++) {
std::cerr << "Calling function " << i << std::endl;
(*fp)(this, ostr);
std::cerr << "Called function " << i << std::endl;
}
PostPrint();
}
class DerClass: public MyClass {
public:
DerClass();
void Func3(std::ostream &ostr) { ostr << "F3" << index << std::endl; };
protected:
void PrePrint() { /* More stuff... */ }
};
// C-cast for conciseness only. Use something safer in the real world.
void DerFunc(MyClass* obj, std::ostream& ostr) { ((DerClass*)obj)->Func3(ostr); }
Printer derclassprinters[] = {
&MyFunc1,
&DerFunc,
NULL
};
DerClass::DerClass()
: MyClass(derclassprinters)
{
}
This uses a pointer member for each instance - I'm assuming you don't want to store the entire function table for every instance.
Related
class CParent {
public:
void Output() {
cout << "I'm Parent!" << endl;
}
virtual void VirtualOutput() {
cout << "I'm Parent!" << endl;
}
};
class CChild : public CParent {
public:
void Output() {
cout << "I'm Child!" << endl;
}
void VirtualOutput() {
cout << "I'm Child!" << endl;
}
};
class CChildChild : public CChild {
public:
void Output() {
cout << "I'm ChildChild!" << endl;
}
void VirtualOutput() {
cout << "I'm ChildChild!" << endl;
}
void CChildOnly() {
cout << "I'm only on ChildChild!" << endl;
}
};
int main() {
CParent cp;
CChild cc;
CChildChild ccc;
CParent* pCP1 = &cp;
CParent* pCP2 = &cc;
CParent* pCP3 = &ccc;
((CChildChild*)pCP1)->CChildOnly(); //<-this code actually works. HOW? WHY?
return 0;
}
The pointer variable 'pCP1' is pointing 'cp' which is 'an object of CParent'. So the 'down casting' doesn't make any sense according to what I've learned.
But it works and shows 'I'm only on ChildChild!' with no problem.
The 'cp' has only 'CParent part' on its memory construct. So it can not be 'down casted' as far as I know.
But it works. How?
This question already has answers here:
What is a converting constructor in C++ ? What is it for?
(3 answers)
Closed 3 years ago.
I am confused how can we pass an integer when the parameter of a function only accept a class of type enemy ( void foo(const Enemy& inKlep ).
Yet when we pass to it an int (300) it compiles. Why is this?
#include <iostream>
using namespace std;
class Enemy {
public:
Enemy() { cout << "E ctor" << endl; }
Enemy(int i) { cout << "E ctor " << i << endl; }
Enemy(const Enemy& src) {cout << "E copy ctor"<< endl;}
Enemy& operator=(const Enemy& rhs) {cout<<"E="<<endl;}
virtual ~Enemy() { cout << "E dtor" << endl; }
void hornet(int i=7) const { // Not virtual!
cout << "E::hornet " << i << endl;
}
};
class Scott : public Enemy {
public:
Scott() : Enemy(1) { cout << "S ctor" << endl; }
Scott& operator=(const Scott& rhs) {cout<<"S="<<endl;}
virtual ~Scott() { cout << "S dtor" << endl; }
void hornet(int i=7) const {
cout<<"S::hornet " << i << endl;
}
};
void foo(const Enemy& inKlep) {
Enemy theEnemy;
inKlep.hornet(2);
}
int main(int argc, char** argv) {
foo(300);
cout << "Done!" << endl; // Don't forget me!
}
In C++, it is valid code for an input parameter to implicitly construct an object if the function expects an object that can be constructed from that parameter. So, for example:
struct CustomInt {
int val;
CustomInt() : CustomInt(0) {}
CustomInt(int value) : val(value) {}
};
void func(CustomInt obj) {
std::cout << obj.val << std::endl;
}
int main() {
func(5); //Valid; will print '5' to the console
}
If you don't want to allow this, you need to add the keyword explicit to the constructor to prevent this.
struct CustomInt {
int val;
CustomInt() : CustomInt(0) {}
explicit CustomInt(int value) : val(value) {}
};
void func(CustomInt obj) {
std::cout << obj.val << std::endl;
}
int main() {
//func(5); //Invalid; will cause a compile-time error
func(CustomInt(5)); //Valid; will print '5' to the console
}
Well, Hospital is the class which has vector of patients.
FemaleIn, FemaleOut, MaleIn, MaleOut are derived classes from patients(Base class). Those classes have toString function(method). What I am trying to do is, in display method in Hospital class, I just want to display only in case of Outpatient which is parent class of FemaleOut and Maleout or Inpatient which is parent class of FemaleIn and MaleIn. From what I am thinking to call only specific method from, for example, Outpatient, I will have to know which objects in which index of vector for automatically. Is there any idea to call only toString for specific class which is, for example, FemaleIn and MaleIn where parent class is Inpatient. Thank you for your any help or suggestion.
void Hospital::determinePatientType()
{
int selection;
cout << endl;
cout << "What is the patient type?" << endl;
cout << "1. Female Inpatient" << endl;
cout << "2. Female Outpatient" << endl;
cout << "3. Male Inpatient" << endl;
cout << "4. Male Outpatient" << endl;
cout << endl;
cin >> selection;
switch(selection)
{
case 1:
patients.push_back(new FemaleIn());
cout << patients.back() << endl;
patients[totalPatients]->enterPatientData();
totalPatients++;
break;
case 2:
patients.push_back(new FemaleOut());
cout << patients.back() << endl;
patients[totalPatients]->enterPatientData();
totalPatients++;
break;
case 3:
patients.push_back(new MaleIn());
cout << patients.back() << endl;
patients[totalPatients]->enterPatientData();
totalPatients++;
break;
case 4:
patients.push_back(new MaleOut());
cout << patients.back() << endl;
patients[totalPatients]->enterPatientData();
totalPatients++;
break;
default:
return;
}
}
void Hospital::display(string type)
{
cout << "Patient Name Spouse Name Sex Patient Type Unit/Appt. Date Diagnosis" << endl;
cout << "===================================================================================" << endl;
if(type=="All")
{
for(int i=0;i<patients.size();i++)
{
patients[i]->toString();
}
}
else if(type=="Outpatient")
{
for(int i=0;i<patients.size();i++)
{
patients[i]->toString();
}
}
else
{
for(int i=0;i<patients.size();i++)
{
patients[i]->toString();
}
}
}
I think this question might be similar to How do I check if an object's type is a particular subclass in C++? .
I would propose something like:
Class Patient{
virtual bool display(string filter);
};
Class OutPatient : Patient {
bool display(string filter) override;
};
bool OutPatient::display(string filter) {
if (filter != "OutPatient")
return false;
//Do stuff
return true;
}
Class InPatient : Patient {
bool display(string filter) override;
};
// You could just make this the default definition on display on Patient
bool InPatient::display(string filter) {
return false;
}
And then:
void Hospital::display(string type)
{
for(auto& patient: patients)
patient->display(type);
}
As quick and dirty way you can use dynamic_cast to certain class pointer to detect whether given instance is of that class:
if (type == "Outpatient")
{
for(int i=0; i<patients.size(); ++i)
{
// try to cast parent class pointer to one of child class
// if one is pointer to that child class p is not nullptr
// otherwise p is nullptr
Outpatient * p = dynamic_cast<Outpatient *>(patients[i]);
if (p) {
p->toString();
}
}
}
For clean way you could use Visitor pattern
Visitor pattern implementation:
#include <iostream>
#include <vector>
#include <string>
#include <functional>
#include <utility>
class AbstractDirectionPatientsDispatcher;
class AbstractGenderPatientDispatcher;
class Patient
{
public:
virtual void accept(AbstractDirectionPatientsDispatcher &dispatcher) = 0;
virtual void accept(AbstractGenderPatientDispatcher &dispatcher) = 0;
std::string name;
};
class InPatient;
class OutPatient;
class AbstractDirectionPatientsDispatcher {
public:
virtual void dispatch(InPatient &patient) = 0;
virtual void dispatch(OutPatient &patient) = 0;
};
class FemalePatient;
class MalePatient;
class AbstractGenderPatientDispatcher {
public:
virtual void dispatch(FemalePatient &patient) = 0;
virtual void dispatch(MalePatient &patient) = 0;
};
template <typename PatientClass, typename Dispatcher>
class CRTPDispatchApplier : virtual public Patient
{
public:
void accept(Dispatcher &dispatcher) override {
dispatcher.dispatch(static_cast<PatientClass &>(*this));
}
};
class InPatient : public CRTPDispatchApplier<InPatient, AbstractDirectionPatientsDispatcher>
{
};
class OutPatient : public CRTPDispatchApplier<OutPatient, AbstractDirectionPatientsDispatcher>
{
};
class FemalePatient : public CRTPDispatchApplier<FemalePatient, AbstractGenderPatientDispatcher>
{
};
class MalePatient : public CRTPDispatchApplier<MalePatient, AbstractGenderPatientDispatcher>
{
};
class InFemale : public FemalePatient, public InPatient
{
};
class OutFemale : public FemalePatient, public OutPatient
{
};
class InMale : public MalePatient, public InPatient
{
};
class OutMale : public MalePatient, public OutPatient
{
};
class DummyDirectionDispatecher : public AbstractDirectionPatientsDispatcher
{
public:
void dispatch(InPatient & ) override {
}
void dispatch(OutPatient & ) override {
}
};
class DummyGenderDispatcher : public AbstractGenderPatientDispatcher
{
public:
void dispatch(FemalePatient &) override {
}
void dispatch(MalePatient &) override {
}
};
template <typename Direction>
class DispatchByDirection : public DummyDirectionDispatecher
{
public:
DispatchByDirection(std::function<void(Direction &)> action) :
m_action(std::move(action))
{}
void dispatch(Direction & p) override {
m_action(p);
}
private:
std::function<void(Direction &)> m_action;
};
template <typename Gender>
class DispatchByGender : public DummyGenderDispatcher
{
public:
DispatchByGender(std::function<void(Gender &)> action) :
m_action(std::move(action))
{}
void dispatch(Gender & p) override {
m_action(p);
}
private:
std::function<void(Gender &)> m_action;
};
int main() {
InFemale f1;
OutFemale f2;
InMale m1;
OutMale m2;
f1.name = "Eve";
f2.name = "Alice";
m1.name = "Bob";
m2.name = "Charlie";
std::vector<Patient *> patients;
patients.push_back(&f1);
patients.push_back(&f2);
patients.push_back(&m1);
patients.push_back(&m2);
DispatchByDirection<InPatient> print_in_patients{[](InPatient &patient){
std::cout << "in: " << patient.name << std::endl;
}};
for (auto p : patients) {
p->accept(print_in_patients);
}
std::cout << std::endl;
DispatchByDirection<OutPatient> print_out_patients{[](OutPatient &patient) {
std::cout << "out: " << patient.name << std::endl;
}};
for (auto p : patients) {
p->accept(print_out_patients);
}
std::cout << std::endl;
DispatchByGender<FemalePatient> print_female{[](FemalePatient &patient) {
std::cout << "female: " << patient.name << std::endl;
}};
for (auto p : patients) {
p->accept(print_female);
}
std::cout << std::endl;
DispatchByGender<MalePatient> print_male{[](MalePatient &patient) {
std::cout << "male: " << patient.name << std::endl;
}};
for (auto p : patients) {
p->accept(print_male);
}
std::cout << std::endl;
}
Using C++ 14, templates and a Bridge pattern, I'm trying to create a generic way of adding objects to a container named Shapes (vector of Shape objects). I would like to be able to automatically support new datatypes which are added to the container and print them without modifying the original implementation of the Shape class. Instead, I would like to only provide a new print(T) function, and everything should work out-of-the-box.
Below is my code, I still have some problems getting it to compile. Can anyone please help me out? Many thanks.
#include <iostream>
#include <memory>
#include <vector>
#include <map>
#include <string>
using namespace std;
void print(const int toPrint) {
cout << " " << toPrint;
cout << endl;
}
void print(const double toPrint) {
cout << " " << toPrint;
cout << endl;
}
void print(const vector<int> & toPrint) {
for (auto & it : toPrint) {
cout << " " << it;
}
cout << endl;
}
void print(const map<int, string> & toPrint) {
for (auto & it : toPrint) {
cout << " " << it.first << " : " << it.second << endl;
}
cout << endl;
}
class Shape {
public:
template<typename T>
Shape(T &&t) {
pimpl_ = make_unique<Specialization<T>>(t);
}
void print() const {
pimpl_->print();
}
private:
struct Base {
virtual void print() const = 0;
virtual ~Base() = default;
};
template<typename T>
struct Specialization: public Base {
Specialization(T &t) :
internalObject_ { std::move(t) } {
}
void print() const override {
::print(internalObject_);
}
T internalObject_;
};
unique_ptr<Base> pimpl_;
};
typedef vector<Shape> Shapes;
void print(Shapes const & shapes) {
for (auto & shape : shapes) {
shape.print();
}
}
int main() {
Shapes shapes;
shapes.push_back(1);
shapes.push_back(2.0);
shapes.push_back(0.3);
shapes.push_back(vector<int> { 10, 11, 12 });
shapes.push_back(map<int, string> { { 0, "elmo" }, { 1, "leom" } });
print(shapes);
return 0;
}
Here is a patched up version of your code which compiles (on clang). As pointed out in the comments there are several issues that need to be addressed (this code leaks memory for example), but this should get you back on track.
#include <iostream>
#include <vector>
using namespace std;
void print(int toPrint) {
cout << " " << toPrint;
cout << endl;
}
void print(double toPrint) {
cout << " " << toPrint;
cout << endl;
}
void print(vector<int> toPrint) {
for (auto & it : toPrint) {
cout << " " << it;
}
cout << endl;
}
class Shape {
public:
template<typename T>
Shape(T t) {
pimpl_ = new Specialization<T>(t);
}
void print() const{
pimpl_->print();
}
private:
struct Base {
virtual void print() const = 0;
};
template<typename T>
struct Specialization: public Base {
Specialization(T t) {
internalObject_ = new T(t);
}
void print() const{
::print(*internalObject_);
}
T* internalObject_;
};
Base * pimpl_;
};
typedef vector<Shape> Shapes;
void print(Shapes const & shapes) {
for (auto & shape : shapes) {
shape.print();
}
}
int main() {
Shapes shapes;
shapes.push_back(1);
shapes.push_back(2.0);
shapes.push_back(0.3);
shapes.push_back(vector<int> { 10, 11, 12 });
print(shapes);
return 0;
}
I am trying to understand how decorator pattern works and how much I can "stretch" it to me needs. Following this example, I have extended classes XYZ. There exist derived classes "KLM" (from XYZ)
Specifically, even though I have a decorator pattern, the derived decorator classes "KLM" have some functionality that does not show up in any of their base classes "XYZ", "D", "I" or "A".
So while normally I would instantiate an object as
I * inKLM = new L( new M( new K( new A )));
This would not allow me to access the K::doVirtR() , L::doVirtS() and M::doVirtT() functions (see code below). To access these I would need to downcast the inKLM pointer using dynamic_cast to each of classes "KLM".
The problem is that I only manage to do this for the leftmost new in the expression above. I have read that polymorphism needs to be maintained in order for the dynamic casting to work, so I have tried to have a virtual destructor in all functions. Still I cannot get the dynamic cast to work for anything other than the "outer" new operation (in this case object of class "L").
Please see this code. How can I make not only "LinKLM" , but also "MinKLM" and "KinKLM" success in dynamic_casting ?
#include <iostream>
#include <list>
using namespace std;
class D; //decorator base
struct I { //interface (for both Base and DecoratorBase
I(){
cout << "\n| I::ctor ";
}
virtual ~I(){
cout << "I::dtor |" ;
}
virtual void do_it() = 0;
virtual void regDecorator(D* decorator) = 0;
virtual void train() = 0;
virtual void et() = 0;
};
class D: public I { //DecoratorBase : has same-named fns as Base (must be exported on I) and calls upon them.
public:
D(I * inner) : m_wrappee(inner) {
cout << "D::ctor ";
regDecorator(this);
}
virtual ~D() {
cout << "D::dtor ";
delete m_wrappee;
}
void do_it() {
m_wrappee->do_it();
}
virtual void et() {
cout << "filling in for lack of et() in derived class\n";
} //almost pure virtual, just not implemented in all derived classes
void train(){
m_wrappee->train();
}
private:
void regDecorator(D* decorator){
m_wrappee->regDecorator(decorator);
}
I * m_wrappee;
};
class A: public I { //Base has all the basic functionality
public:
A() {
cout << "A::ctor " ;
decList.clear();
}
~A() {
cout << "A::dtor |" ;
}
void do_it() {
cout << 'A';
}
void train(){
et();
}
void regDecorator(D* decorator)
{
if (decorator) {
cout << "reg=" << decorator << " ";
decList.push_back(decorator);
}
else
cout << "dec is null!" <<endl;
}
private:
void et()
{
//size_t counter=0;
list<D*>::iterator it;
for( it=decList.begin(); it != decList.end(); it++ )
{
//if ( (*it)->et() )
(*it)->et();
//else
// cout << "couldnt et cnt=" << counter << endl;
//counter++;
}
}
std::list<D*> decList;
};
class X: public D { //DerivedDecoratorX ..
public:
X(I *core): D(core){
cout << "X::ctor ";
}
virtual ~X() {
cout << "X::dtor ";
}
void do_it() {
D::do_it();
cout << 'X';
}
void doX() {
cout << "doX" << endl;
}
protected:
virtual void doVirtR() = 0;
private:
void et(){
cout << "X::et" <<endl;
}
};
class K: public X {
public:
K(I * core):X(core) {
cout << "K::ctor " ;
}
virtual ~K() {
cout << "K::dtor ";
}
void doVirtR(){
cout << "doVirtK" <<endl;
}
};
class Y: public D {
public:
Y(I *core): D(core){
cout << "Y::ctor ";
}
virtual ~Y() {
cout << "Y::dtor ";
}
/*void et(){
cout << "Y::et" <<endl;
}*/
void do_it() {
D::do_it();
cout << 'Y';
}
void doY() {
cout << "doY" << endl;
}
protected:
virtual void doVirtS() = 0;
};
class L: public Y{
public:
L(I * core):Y(core) {
cout << "L::ctor ";
}
virtual ~L() {
cout << "L::dtor ";
}
void doVirtS(){
cout << "doVirtL" <<endl;
}
};
class Z: public D {
public:
Z(I *core): D(core){
cout << "Z::ctor ";
}
virtual ~Z() {
cout << "Z::dtor ";
}
void et(){
cout << "Z::et" <<endl;
}
void do_it() {
D::do_it();
cout << 'Z';
}
void doZ() {
cout << "doZ" << endl;
}
virtual void doVirtT() = 0;
};
class M: public Z{
public:
M(I * core):Z(core) { //must add D(core) here explicitly because of virtual inheritance in M's base class (Z).
cout << "M::ctor " ;
}
virtual ~M() {
cout << "M::dtor ";
}
void doVirtT(){
cout << "doVirtM" <<endl;
}
};
int main(void) //testing dynamic casting
{
I * inKLM = new L( new M( new K( new A )));
L * LinKLM = dynamic_cast<L *>( inKLM);
M * MinKLM = dynamic_cast<M *>( inKLM);
K * KinKLM = dynamic_cast<K *>( inKLM);
cout << endl;
if ( ! MinKLM ) cout << "null MinKLM!" << endl;
if ( ! LinKLM ) cout << "null LinKLM!" << endl;
if ( ! KinKLM ) cout << "null KinKLM!" << endl;
//KinKLM->doVirtR();
//LinKLM->doVirtS();
//MinKLM->doVirtT();
//LinKLM->D::train();
//KinKLM->do_it();
//MinKLM->doZ();
delete inKLM;
cout << endl;
return 0;
}
If you need access to functionality that is unique in some of the inner classes, you may be better off (depending on the particular problem) trying mixin classes. The basic idea is to have a template class inherit its template parameter. I have simplified the classes below but the principle is clear:
#include <iostream>
// your base class
class I {
public:
virtual void do_it() {}
};
// a decorator
template <class Base>
class T1 : public Base {
public:
void do_it() {
std::cout << "T1" << std::endl;
Base::do_it();
}
void unique_in_T1() {
std::cout << "Unique in T1" << std::endl;
}
};
// another decorator
template <class Base>
class T2 : public Base {
public:
void do_it() {
std::cout << "T2" << std::endl;
Base::do_it();
}
void unique_in_T2() {
std::cout << "Unique in T2" << std::endl;
}
};
// yet another decorator
template <class Base>
class T3 : public Base {
public:
void do_it() {
std::cout << "T3" << std::endl;
Base::do_it();
}
void unique_in_T3() {
std::cout << "Unique in T3" << std::endl;
}
};
int main(int argc, const char * argv[]) {
T3<T2<T1<I>>> my_object1;
my_object1.do_it();
my_object1.unique_in_T2();
T1<T3<I>> my_object2;
my_object2.do_it();
my_object2.unique_in_T3();
return 0;
}
Your class D is not needed anymore. The main purpose of that class is to wrap the object that actually does the job while maintaining the interface of I. With mixin classes there is no wrapping anymore as it has been replaced by inheritance, hence there is no need for the D class.
Here is a link to read more.