I need some advice on the design of my class hierarchy. The 'skeleton' of my current design is
template <class X>
class BASE {
public:
virtual void f() {
x_.f2(m_);
}
void g() {
/* do stuff here*/
x_.g();
}
/* more member functions here*/
protected:
X x_;
int m_;
};
template <class X>
class DERIVED : BASE<X> {
public:
virtual f() override {
x_.f1();
}
protected:
using BASE<X>::x_;
using BASE<X>::m_;
};
and finally I have two more classes like this
struct X1 {
void f1();
void g();
};
struct X2 : X1 {
void f2(int m);
};
I would like to be able to create an instance of DERIVED<X1>
. To do that, the compiler will create first an instance of BASE<X1>
, in which case it will complain that X1 does not have a member function f2 (even though in practice it would never be called since the calling function f() is virtual).
I understand that this is a bad design since in order to have a templated class, the template arguments must have the same interface. In my case X1 and X2 have a common interface but X2 has more functionality, which creates the above problem. I understand I could create an f2 function in X1 which does nothing, but ideally I would like to avoid that.
I would welcome any suggestions for improving the design. Thanks in advance!
Avoid deriving from a concrete class. Lift interfaces/ABCs to the top, make all concrete classes leaves. It's a general advice for many kinds of design difficulties.
In your particular case, instead of this:
BASE // concrete
|
DERIVED
use this:
BASE // fully abstract
/ \
BASIC_DERIVED ADVANCED_DERIVED
Now f
is pure virtual in BASE
and all is well.
First advice is not to use protected atributes. Is is breaking incapsulation.
The second advice is to make virtual void f()=0
pure virtual without implementation. In such there will be no error in the derived class.
I need some advice on the design of my class hierarchy. The 'skeleton' of my current design is
template <class X>
class BASE {
public:
virtual void f() {
x_.f2(m_);
}
void g() {
/* do stuff here*/
x_.g();
}
/* more member functions here*/
protected:
X x_;
int m_;
};
template <class X>
class DERIVED : BASE<X> {
public:
virtual f() override {
x_.f1();
}
protected:
using BASE<X>::x_;
using BASE<X>::m_;
};
and finally I have two more classes like this
struct X1 {
void f1();
void g();
};
struct X2 : X1 {
void f2(int m);
};
I would like to be able to create an instance of DERIVED<X1>
. To do that, the compiler will create first an instance of BASE<X1>
, in which case it will complain that X1 does not have a member function f2 (even though in practice it would never be called since the calling function f() is virtual).
I understand that this is a bad design since in order to have a templated class, the template arguments must have the same interface. In my case X1 and X2 have a common interface but X2 has more functionality, which creates the above problem. I understand I could create an f2 function in X1 which does nothing, but ideally I would like to avoid that.
I would welcome any suggestions for improving the design. Thanks in advance!
Avoid deriving from a concrete class. Lift interfaces/ABCs to the top, make all concrete classes leaves. It's a general advice for many kinds of design difficulties.
In your particular case, instead of this:
BASE // concrete
|
DERIVED
use this:
BASE // fully abstract
/ \
BASIC_DERIVED ADVANCED_DERIVED
Now f
is pure virtual in BASE
and all is well.
First advice is not to use protected atributes. Is is breaking incapsulation.
The second advice is to make virtual void f()=0
pure virtual without implementation. In such there will be no error in the derived class.
0 commentaires:
Enregistrer un commentaire