I have a class baseNoCrtpIterator
that holds one member baseNoCrtp _base
, among others.
Class baseNoCrtp
has several simply derived classes derived[n]NoCrtp
, where [n]
denotes a number 1,2,... These classes do not add any data members to baseNoCrtp
, only some functionality.
I want that, during construction of a baseNoCrtpIterator
, member _base
is assigned one of derived[n]NoCrtp
, depending on another value dclass
passed to the constructor.
Is that possible?
I tried a constructor like
baseNoCrtpIterator::baseNoCrtpIterator(const int dclass) :
_base(dclass) // Point #8
{
if (dclass == 0) {
derived1NoCrtp* d1n = new derived1NoCrtp(0);
_base = *d1n; // Point #9
}
else if (dclass == 1) {
derived2NoCrtp* d2n = new derived2NoCrtp(1);
_base = *d2n;
} else {
cout << "Unknown derived class: " << dclass << endl;
throw runtime_error("Unknown derived class");
}
};
This doesn't work, and I probably have to fix #8 (I guess I have to remove it from the initializer list), and #9, since I don't have operator=
(I could write it, but I guess it doesn't solve my problem).
Note: I guess CRTP might be an alternative. But I see a couple of problems:
- All uses of
baseNoCrtpIterator
have to be replaced bybaseNoCrtpIterator<T>
. Thus, downstream, all functions, classes, etc., that usebaseNoCrtpIterator
will have to be "templetized". This means huge changes in existing code. - I would not be able to hold all objects of class
baseNoCrtp
and derived in a single container. That is part of the changes mentioned above.
TL;DR
I have two hierarchies of (base + n simply derived) classes. One is a "main" hierarchy, and the other is an "iterator" hierarchy, meant to iterate over the main.
The base class for the iterators refers to the base class for the main in #1
class baseNoCrtpIterator {
public:
baseNoCrtpIterator(const baseNoCrtp& base, const int dclass);
virtual ~baseNoCrtpIterator() {};
const baseNoCrtp& operator*() const { return *operator->(); };
const baseNoCrtp* operator->() const { return &_base; };
private:
baseNoCrtp _base; // Point #1
int _index;
};
and its constructor is
baseNoCrtpIterator::baseNoCrtpIterator(const structure& s, const int dclass) :
_base(s, dclass),
_index(0) { };
where dclass
indicates the derived class of _base
(that is not enough, as will be shown later).
The derived iterator classes are like this (derived1...
is associated with dclass=0
, and so on)
class derived1NoCrtpIterator : public baseNoCrtpIterator { // derived1...
public:
derived1NoCrtpIterator(const baseNoCrtp& base) : baseNoCrtpIterator(base, 0) {}; // ... dclass=0
virtual ~derived1NoCrtpIterator() {};
const derived1NoCrtp& operator*() { return *operator->(); }
const derived1NoCrtp* operator->() { // Point #2
const baseNoCrtp* bnp = baseNoCrtpIterator::operator->(); // Point #3
return static_cast<const derived1NoCrtp*>(bnp); // Point #4
}
};
The problem is when using something like
for (derived1NoCrtpIterator d1ni(sconst); ...) {
const derived1NoCrtp& d1nr = *d1ni; // Point #5
...
Point #5 leads to #2.
In #3 we extract a pointer to member baseNoCrtp
.
But then the static_cast
downcast in #4 is undefined behavior.
This could be solved if the constructor baseNoCrtpIterator::baseNoCrtpIterator
assigned to baseNoCrtp
objects of the derived classes derived1NoCrtpIterator
, etc., instead of the base class.
I tried to replace the constructor with something like
baseNoCrtpIterator::baseNoCrtpIterator(const structure& s, const int dclass) :
_base(s, dclass), // Point #8
_index(0) {
if (dclass == 0) {
derived1NoCrtp* d1n = new derived1NoCrtp(s, 0);
_base = *d1n; // Point #9
}
else if (dclass == 1) {
derived2NoCrtp* d2n = new derived2NoCrtp(s, 1);
_base = *d2n;
} else {
cout << "Unknown derived class: " << dclass << endl;
throw runtime_error("Unknown derived class");
}
};
This doesn't work, and I probably have to fix #8 (I guess I have to remove it from the initializer list), and #9, since I don't have operator=
(I could write it, but I guess it doesn't solve my problem).
How can I achieve this assignment to _base
of objects of derived classes, depending on dclass
?
Since this is a boiled down example of a very large code that I have to fix, I am in principle not interested in other methods that require extensive modifications of the code. For instance, if CRTP might be a solution, it probably involves huge changes. I know the current way might be a somewhat contrived form of iterating the main hierarchy, but this is what I received.
The "main" classes are (here it is not relevant what structure
is):
class baseNoCrtp {
public:
baseNoCrtp(const structure& s, const int dclass) :
_structure(s), _derivedClass(dclass) { };
virtual ~baseNoCrtp() {};
public:
int getDerivedClass() const { return _derivedClass; }
const structure& getStructure() const { return _structure; };
protected:
const structure& _structure;
private:
friend class baseNoCrtpIterator;
int _derivedClass;
};
class derived1NoCrtp : public baseNoCrtp {
public:
derived1NoCrtp(const structure& s) : baseNoCrtp(s, 0) {};
virtual ~derived1NoCrtp() {};
// Add whatever extra methods
};