I have an abstract class Object, which looks like this:
class Object
{
public:
Object();
virtual void DoSomething() = 0;
virtual void Save(std::ofstream &file) = 0;
virtual void Load(std::ifstream &file) = 0;
};
I also have classes Ball and TextBox:
class Ball : public Object
{
public:
Ball(int x, int y, int z)
{
m_x = x; m_y = y; m_z = z;
}
void DoSomething()
{
std::cout << m_x << ", " << m_y << ", " << m_z << std::endl;
}
void Save(std::ofstream &file)
{
file << m_x << " " << m_y << " " << m_z << std::endl;
}
void Load(std::ifstream &file)
{
file >> m_x >> m_y >> m_z;
}
private:
int m_x, m_y, m_z;
};
class TextBox: public Object
{
public:
TextBox(std::string message)
{
m_message = message;
}
void DoSomething()
{
std::cout << m_message << std::endl;
}
void Save(std::ofstream &file)
{
file << m_message << std::endl;
}
void Load(std::ifstream &file)
{
file >> m_message;
}
private:
std::string m_message;
};
I have a vector of pointers to theese objects:
std::vector<Object*> objects;
objects.push_back(new Ball(1, 2, 3));
objects.push_back(new TextBox("Hello world!"));
for (Object *o : objects) o->DoSomething();
I want to save this vector to file. This is very easy. I make something like this:
std::ofstream file("foo.txt");
for (Object *o : objects) o->Save(file);
file.close();
Now I want to load this. And here is a problem. How I can specify, which object (Ball or TextBox) I supposed to load? I could use some indexes, like that:
void Ball::Save(std::ofstream &file)
{
file << 1 << " " << m_x << " " << m_y << " " << m_z << std::endl;
}
void TextBox::Save(std::ofstream &file)
{
file << 2 << " " << m_message << std::endl;
}
Then, after reading this index, I know, that this is a Ball or a TextBox.
int index;
Object *o;
file >> index;
switch (index)
{
case 1: o = new Ball(0, 0, 0); break;
case 2: o = new TextBox(""); break;
}
o->Load(file);
objects.push_back(o);
But is there a better way to store this structure? What if I have 100 inheritors of Object? Can I somehow avoid 100-switch case?
These 'indexes' you came up with are usually called 'metadata'. There are other languages, like java, that support reflection for that purpose but in C++ reflection in still under consideration. For that reason, I would suggest implementing sort of an abstract interface that would return information of the exact class of an object.
Furthermore, I would suggest looking at serialization libraries, that could ease the process of saving and reading data. You can try to start with boost:
https://www.boost.org/doc/libs/1_73_0/libs/serialization/doc/index.html
I must admit that I used boost serialization a long time ago, but I remember it was quite easy to use.
Related
I want to print some strings in functions, but indented depending on how far the depth of the function calls has gone. My solution so far includes a class from this thread like the following:
class DepthCounter
{
static int depth;
public:
DepthCounter(const std::string& name)
{
std::cout << std::string(depth*2, ' ') << name << " // depth " << depth << '\n';
++depth;
}
~DepthCounter()
{
--depth;
}
};
int DepthCounter::depth = 0;
void func1(){
DepthCounter dc("name1");
}
void func2(){
DepthCounter dc("name2");
func1();
}
so the print in the first construction will have 1 depth and the second one 2 depth (indent).
but I want to make this print multiple times. that is
void func2(){
DepthCounter dc("name0");
DepthCounter dc1("name1");
DepthCounter dc2("name2");
DepthCounter dc3("name3");
func1();
}
but I don't find it nice, let alone the fact that this construction increases the depth although it is still in the same function. Is there a better way do have such functionality?
ideally I want something like:
void func1(){
funcX("name5");
}
void func2(){
funcX("name0");
funcX("name1");
funcX("name2");
funcX("name3");
func1();
}
Does anyone know an alternative way?
You could store the function name inside the DepthCounter and provide an operator<< overload to use inside the functions:
class DepthCounter {
static int depth;
std::string m_name;
public:
DepthCounter(const std::string& name) : m_name(name) {
std::cout << std::string(depth*2, ' ') << "->" << m_name << '\n';
++depth;
}
~DepthCounter() {
--depth;
std::cout << std::string(depth*2, ' ') << "<-" << m_name << '\n';
}
template<class T>
friend DepthCounter& operator<<(DepthCounter& dc, const T& val) {
std::cout << std::string(depth*2, ' ') << dc.m_name << ": " << val << '\n';
return dc;
}
};
int DepthCounter::depth = 0;
And use it like so:
void func1(){
DepthCounter dc(__func__);
dc << "here's something";
}
void func2(){
DepthCounter dc(__func__);
dc << "name1";
dc << "name2";
func1();
dc << "some more after calling func1";
}
Demo
For some reason I cannot use functions attached to the object I want to use. I added a comment to the line that is not working. As an error I get "Error; pointer to incomplete class type is not allowed" Please help
This is code in dokter.ccp
int counter = 0;
for (list<Wielrenner*>::iterator it = wielrenners.begin(); it != wielrenners.end(); it++){
Wielrenner* wielrennerOB = *it;
cout << "\nID: " << counter;
cout << "List size: " << persons.size() << endl;
wielrennerOB->print(); // This is not working
counter++;
}
This is code in wielrenner.h
#ifndef WIELRENNER_H_
#define WIELRENNER_H_
//#include <fstream>
#include "persoon.h"
#include "Onderzoek.h"
class Wielrenner :
public Persoon
{
public:
Wielrenner(string, string, Adres, string, Datum, Datum, string, int, float, float, float,list<Onderzoek>* );
~Wielrenner(void);
int getLengte() const;
float getGewicht() const;
float getVo2max() const;
float getMaxVermogen() const;
list<Onderzoek> getOnderzoekenList();
void setLengte(int);
void setGewicht(float);
void setVo2max(float);
void setMaxVermogen(float);
void voegOnderzoekToeList(Onderzoek);
void showOnderzoeksList();
void setOnderzoeksLijst(list<Onderzoek>&);
void print();
void printFile(ofstream&);
private:
int lengte;
float gewicht;
float vo2max;
float maxVermogen;
list<Onderzoek> onderzoeken;
};
#endif /* WIELRENNER_H_ */
code in wielrenner.CCP
using namespace std;
#include <string>
#include "Wielrenner.h"
/*
#include "Onderzoek.h"
*/
Wielrenner::Wielrenner(string voornaam, string achternaam, Adres adres, string telefoon, Datum datumInDienst, Datum geboorteDatum,
string persoonType, int lengte, float gewicht, float vo2max, float maxVermogen,list<Onderzoek>* onderzoeken)
: lengte(lengte),
gewicht(gewicht),
vo2max(vo2max),
maxVermogen(maxVermogen),
Persoon(voornaam, achternaam, adres, telefoon, datumInDienst, geboorteDatum, persoonType)
{
}
Wielrenner::~Wielrenner(void)
{
}
//setten van gegevens
void Wielrenner::setLengte(int newLengte){
lengte = newLengte;
}
void Wielrenner::setGewicht(float newGewicht){
gewicht = newGewicht;
}
void Wielrenner::setVo2max(float newVo2max){
vo2max = newVo2max;
}
void Wielrenner::setMaxVermogen(float newMaxVermogen){
maxVermogen = newMaxVermogen;
}
void Wielrenner::voegOnderzoekToeList(Onderzoek newOnderzoek){
onderzoeken.push_back(newOnderzoek);
}
void Wielrenner::showOnderzoeksList(){
int teller=0;
for (list<Onderzoek>::iterator it = onderzoeken.begin(); it != onderzoeken.end(); it++){
Onderzoek onderzoekOB = *it;
cout << teller << " - ";
onderzoekOB.print();
teller++;
}
}
void Wielrenner::setOnderzoeksLijst(list<Onderzoek>& newOnderzoeksLijst){
onderzoeken = newOnderzoeksLijst;
}
void Wielrenner::print(){
cout << "(" << persoonID << ") Persoon: " << endl;
cout << persoonType << endl;
cout << voornaam << " " << achternaam << endl;
adres.print();
cout << telefoon << endl;
cout << "Datum in dienst: ";
datumInDienst.print();
cout << "Geboortedatum: ";
geboorteDatum.print();
cout << "> Extra wielrenner gegevens: " << endl;
cout << "Lengte: " << lengte << endl;
cout << "Gewicht: " << gewicht << endl;
cout << "vo2max: " << vo2max << endl;
cout << "maxVermogen: " << maxVermogen << endl;
}
void Wielrenner::printFile(ofstream &myfile){
myfile << persoonID << "\n";
myfile << persoonType << "\n";
myfile << voornaam << " " << achternaam << "\n";
adres.printFile(myfile);
myfile << telefoon << "\n";
datumInDienst.printFile(myfile);
geboorteDatum.printFile(myfile);
myfile << lengte << "\n";
myfile << gewicht << "\n";
myfile << vo2max << "\n";
myfile << maxVermogen << "\n";
}
// returnen van gegevens
int Wielrenner::getLengte() const{
return lengte;
}
float Wielrenner::getGewicht() const{
return gewicht;
}
float Wielrenner::getVo2max() const{
return vo2max;
}
float Wielrenner::getMaxVermogen() const{
return maxVermogen;
}
list<Onderzoek> Wielrenner::getOnderzoekenList(){
return onderzoeken;
}
An "incomplete class" is one declared but not defined. E.g.
class Wielrenner;
as opposed to
class Wielrenner
{
/* class members */
};
You need to #include "wielrenner.h" in dokter.ccp
One thing to check for...
If your class is defined as a typedef:
typedef struct myclass { };
Then you try to refer to it as struct myclass anywhere else, you'll get Incomplete Type errors left and right. It's sometimes a mistake to forget the class/struct was typedef'ed. If that's the case, remove "struct" from:
typedef struct mystruct {}...
struct mystruct *myvar = value;
Instead use...
mystruct *myvar = value;
Common mistake.
You get this error when declaring a forward reference inside the wrong namespace thus declaring a new type without defining it. For example:
namespace X
{
namespace Y
{
class A;
void func(A* a) { ... } // incomplete type here!
}
}
...but, in class A was defined like this:
namespace X
{
class A { ... };
}
Thus, A was defined as X::A, but I was using it as X::Y::A.
The fix obviously is to move the forward reference to its proper place like so:
namespace X
{
class A;
namespace Y
{
void func(X::A* a) { ... } // Now accurately referencing the class`enter code here`
}
}
The problem also occurs when header files are not included explicitly where they are needed, but implicitly through other heading files.
I came accross the same problem and solved it by checking my #includes.
If you use QKeyEvent you have to make sure that you also include it.
I had a class like this and my error appeared when working with "event"in the .cpp file.
myfile.h
#include <QKeyEvent> // adding this import solved the problem.
class MyClass : public QWidget
{
Q_OBJECT
public:
MyClass(QWidget* parent = 0);
virtual ~QmitkHelpOverlay();
protected:
virtual void keyPressEvent(QKeyEvent* event);
};
Check out if you are missing some import.
This question already has answers here:
When to use virtual destructors?
(20 answers)
Closed 5 years ago.
I'm trying to implement autorelease pool in c++, and have trouble with deallocating.
So we have root-class object:
class object {
public:
object() {
retainCount_ = 0;
}
~object() {
std::cout << "object " << Description() << " is dealocated" << std::endl;
}
/* code with retain/release here */
int retainCount() {
return retainCount_;
}
std::string Description() {
std::stringstream ss;
ss << this;
return ss.str();
}
private:
int retainCount_;
};
And some realization:
class Integer : public object {
public:
int i;
Integer(int ii) : i(ii) {}
~Integer() {
std::cout << "Integer " << Description() << " is dealocated" << std::endl;
}
};
And of course release pool class, which works with root-class pointers:
class release_pool {
public:
void insert(object* obj) {
pointers_.insert(obj);
}
void flush() {
std::set<object*>::iterator it = pointers_.begin();
std::set<object*>::iterator tmp;
const int N = pointers_.size();
for (int i = 0; i < N; i++) {
tmp = it;
it++;
if ((*tmp)->retainCount() == 0 ) {
object* obj = *tmp;
std::cout << "delete obj: " << obj->Description() << std::endl;
pointers_.erase(tmp);
delete obj;
}
}
}
private:
std::set<object*> pointers_;
};
main.cpp code for test:
int main () {
release_pool pool;
Integer* obj = new Integer(5);
pool.insert(obj);
std::cout << "before flush: " << obj->i << "\n";
pool.flush();
std::cout << "after flush: " << obj->i << "\n";
return 0;
}
After build, I get next:
before flush: 5
delete obj: 0x7f9a84c025d0
object 0x7f9a84c025d0 is dealocated
after flush: 5
At the end: destructor of root-class is invoked, but of Integer not. Hence, we have leaked memory, which is allocated for Integer object. Have you any ideas to fix it? How i can delete whole object, not root-part of it.
You need to make your object destructor virtual.
First off: I know that it is generally a bad idea to change an object's class, but I'm implementing my own programming language, and it has variables that can contain values of any type, and even change their type at will, so please assume I'm not a beginner not understanding OO basics.
Currently, I implement my variant variables in C. Each one has a pointer to a table of function pointers, containing functions like SetAsInt(), SetAsString() etc., followed by what would be instance variables in C++. All objects are the same size.
When a variable contains a string and someone assigns an Int to it, I manually call the destructor, change the table of function pointers to point to the table used for variadic int values, and then set its int instance variable.
This is a bit hard to maintain, as every time I add a new type, I have to add a new table of function pointers and fill out all the function pointers in it. Structs of function pointers seem to be very badly type-checked, and missing fields don't lead to complaints, so I can easily accidentally forget one pointer in the list and get interesting crashes. Also, I have to repeat all the function pointers that are the same in most types.
I'd like to implement my variadic types in C++ instead, where a lot of this type-checking and inheriting default behaviours is done for me by the compiler. Is there a safe way to do this?
PS - I know I could create a wrapper object and use new to allocate a new object, but I can't have the additional extra allocation overhead for every int variable on the stack.
PPS - The code needs to be portable across Linux, Mac, iOS and Windows for now, but if someone has a standard C++ solution, that would be even better.
PPPS - The list of types is extensible, but predetermined at compile-time. The base layer of my language defines just the basic types, but the host application my language is compiled into adds a few more types.
Usage Example:
CppVariant someNum(42); // Creates it as CppVariantInt.
cout << "Original int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsInt(700); // This is just a setter call.
cout << "Changed int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsDouble(12.34); // This calls destructor on CppVariantInt and constructor on CppVariantDouble(12.34).
cout << "Converted to Double: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl; // GetAsInt() on a CppVariantDouble() rounds, or whatever.
(Imagine that beyond double and int, there would be other types in the future, like strings or booleans, but the caller of GetAsInt()/SetAsInt() shouldn't have to know what it is stored as, as long as it can be converted at runtime)
Here is a solution based on type-erasure, union and template specializations.
I'm not sure it fits your requirements.
Anyway, here is what it gets:
Anything is placed on the dynamic storage
No hierarchy required
You can easily improve it further to reduce the amount of code, but this aims to serve as a base point from which to start.
It follows a minimal, working example based on the intended use in the question:
#include<iostream>
class CppVariant {
union var {
var(): i{0} {}
int i;
double d;
};
using AsIntF = int(*)(var);
using AsDoubleF = double(*)(var);
template<typename From, typename To>
static To protoAs(var);
public:
CppVariant(int);
CppVariant(double);
int getAsInt();
double getAsDouble();
void setAsInt(int);
void setAsDouble(double);
private:
var data;
AsIntF asInt;
AsDoubleF asDouble;
};
template<>
int CppVariant::protoAs<int, int>(var data) {
return data.i;
}
template<>
int CppVariant::protoAs<double, int>(var data) {
return int(data.d);
}
template<>
double CppVariant::protoAs<int, double>(var data) {
return double(data.i);
}
template<>
double CppVariant::protoAs<double, double>(var data) {
return data.d;
}
CppVariant::CppVariant(int i)
: data{},
asInt{&protoAs<int, int>},
asDouble{&protoAs<int, double>}
{ data.i = i; }
CppVariant::CppVariant(double d)
: data{},
asInt{&protoAs<double, int>},
asDouble{&protoAs<double, double>}
{ data.d = d; }
int CppVariant::getAsInt() { return asInt(data); }
double CppVariant::getAsDouble() { return asDouble(data); }
void CppVariant::setAsInt(int i) {
data.i = i;
asInt = &protoAs<int, int>;
asDouble = &protoAs<int, double>;
}
void CppVariant::setAsDouble(double d) {
data.d = d;
asInt = &protoAs<double, int>;
asDouble = &protoAs<double, double>;
}
int main() {
CppVariant someNum(42);
std::cout << "Original int: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
someNum.setAsInt(700);
std::cout << "Changed int: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
someNum.setAsDouble(12.34);
std::cout << "Converted to Double: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
}
On a lark, I tried using placement new to do this, and I have ... something ... It compiles, it does the job, but I'm not sure if it's an improvement over pure C. Since I can't have a union of C++ objects, I create a CPPVMAX() macro to pass the largest sizeof() of all subclasses as the size to mBuf[], but that's not really pretty either.
#include <iostream>
#include <string>
#include <cmath>
#define CPPVMAX2(a,b) (((a) > (b)) ? (a) : (b))
#define CPPVMAX3(a,b,c) CPPVMAX2((a),CPPVMAX2((b),(c)))
using namespace std;
class CppVariantBase
{
public:
CppVariantBase() { cout << "CppVariantBase constructor." << endl; }
virtual ~CppVariantBase() { cout << "CppVariantBase destructor." << endl; }
virtual int GetAsInt() = 0;
virtual double GetAsDouble() = 0;
virtual void SetAsInt( int n );
virtual void SetAsDouble( double n );
};
class CppVariantInt : public CppVariantBase
{
public:
CppVariantInt( int n = 0 ) : mInt(n)
{
cout << "CppVariantInt constructor." << endl;
}
~CppVariantInt() { cout << "CppVariantInt destructor." << endl; }
virtual int GetAsInt() { return mInt; }
virtual double GetAsDouble() { return mInt; }
virtual void SetAsInt( int n ) { mInt = n; }
protected:
int mInt;
};
class CppVariantDouble : public CppVariantBase
{
public:
CppVariantDouble( double n = 0 ) : mDouble(n)
{
cout << "CppVariantDouble constructor." << endl;
}
~CppVariantDouble()
{
cout << "CppVariantDouble destructor." << endl;
}
virtual int GetAsInt()
{
if( int(mDouble) == mDouble )
return mDouble;
else
return round(mDouble);
}
virtual double GetAsDouble() { return mDouble; }
virtual void SetAsDouble( int n ) { mDouble = n; }
protected:
double mDouble;
};
class CppVariant
{
public:
CppVariant( int n = 0 ) { new (mBuf) CppVariantInt(n); }
~CppVariant() { ((CppVariantBase*)mBuf)->~CppVariantBase(); }
operator CppVariantBase* () { return (CppVariantBase*)mBuf; }
CppVariantBase* operator -> () { return (CppVariantBase*)mBuf; }
protected:
uint8_t mBuf[CPPVMAX3(sizeof(CppVariantBase),sizeof(CppVariantInt),sizeof(CppVariantDouble))];
};
void CppVariantBase::SetAsInt( int n )
{
this->~CppVariantBase();
new (this) CppVariantInt(n);
}
void CppVariantBase::SetAsDouble( double n )
{
this->~CppVariantBase();
new (this) CppVariantDouble(n);
}
int main(int argc, const char * argv[]) {
CppVariant someNum(42);
cout << "Original int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsInt(700); // This is just a setter call.
cout << "Changed int: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
someNum->SetAsDouble(12.34); // This changes the class to CppVariantDouble.
cout << "Converted to Double: " << someNum->GetAsInt()
<< " (" << someNum->GetAsDouble() << ")" << endl;
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.