I've gotten myself conceptually stuck in trying to convert a working C++ program from a C-style approach to one using inheritance and polymorphism. In particular, the problem revolves around using base class pointer vectors to contain pointers to particular derived class objects. A given base class pointer vector will only contain pointers to one specific derived class, but there is one such vector for each derived class.
The previous implementation looked like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
struct L{
int row, col;
// () and (int, int) constructors
};
struct B{
L where;
int** matrixA;
// (), (int, int) (const L&) constructors which also initialize matrixA to NULL
// and a function to compare an external L obj with where
};
enum bType {Type1, Type2, ..., TypeN};
vector<L> tempL1, tempL2, ..., tempLN; // these are filled at start of turn elsewhere in prog
vector<B> B1, B2, ..., BN; // these are matched with tempLx vectors and Typex bType
// and are used as persistent storage of the values in the tempL vectors
|
and within the function that calculates a single player-move
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
fillUpTempLs(); // based on parsing of piped stdin game codes
if(turn==1)
{
create(B1, tempL1, Type1);
...
create(BN, tempLN, TypeN);
}
else
{
reconcile(B1, tempL1, Type1);
...
reconcile(BN, tempLN, TypeN);
}
// rest of move func.
|
The functions
create and
reconcile work as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
create(vector<B>& BB, vector<L>& LL, const bType bT)
{
// for each entry in LL, create element in BB
// based on bT, alloc or don't memory for matrix1
// if using matrix1, call fcn to prepare for filling it
// when ready, fill matrix1 according to bT
// then "publish" values in matrix1 to a larger game map overlay
LL.clear();
};
reconcile(vector<B>& BB, vector<L>& LL, const bType bT)
{
// step through BB
// step through LL looking for BB[i], if found erase LL[j] and go to next BB
// if not found, either do nothing or mark BB[i] for destruction
// end loop
// remove all entries in BB marked for destruction after unpublishing matrix1 values and
// delete[] matrix1 in steps
create(BB,LL,bT); // add the remaining LL elements into BB
};
|
This is what I was using, and it worked fine until I discovered that I wanted B3 to have an extra variable, and realized other "types" might also require different structures.
So I now have:
1 2 3 4 5 6 7 8 9 10 11
|
class A
{
int row, col;
//constructors
}
class B:public A
{
int** matrix1;
//constructors
}
class D1:public B {/*constructors*/} // also classes D2,..., DN
|
and I'm changing B1,...,BN to vector<B*>'s, so
create and
reconcile arg list is now (vector<B*>&,vector<L>&) hopefully without using bType at all.
Now I understand how to use a base class pointer vector to hold the values of "new D1(...)", and how I can use pure virtual fcns in B with over-ridden implementations in D1, D2, etc. but I'm totally stuck on one particular issue.
I want to rewrite the functions
create and
reconcile so that I use the pure virtual methods in B to remove the switch/case parts, and keep only the generic code (or move some of that too into B), but I can't for the life of me figure out how to actually call "new DerivedClass" within
create without naming the actual class Di, which means I can't do without the enum const in the arg list. I could move that part perhaps to my main makeMove() fcn, but that defeats the purpose of hiding it all away in
create and
reconcile (which actually calls
create itself).
Am I missing something here? I don't see implementing what I want in either B or the Di's, but perhaps I'm wrong about that -- I mean, B is not supposed to be aware of the Di classes, and Di can't call "new Di" within its own methods, can it?
Any help would be greatly appreciated. Thanks.
EDIT: I'm not sure if I was mistaken here: "Di can't call "new Di" within its own methods". In the Marshall Cline C++ FAQ I found a discussion of "virtual constructors":
http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.8 Is that what I'm looking for? And clearly I
can call "new Di" within Di, and return a pointer to Di, so maybe that's the way to go?