C++ enforce conditions on inherited classes
I would like to define an abstract base class X and enforce the following:
a) every concrete class Y that inherits from X define a constructor Y(int x)
b) it should be possible to test whether two Y objects are equal.
For a, one not very good solution is to put a pure virtual fromInt method in X which concrete class will have to define. But I cannot enforce construction.
For b), I cannot seem to use a pure virtual method in X
bool operator == (const X& other) const =0;
because in overr开发者_高级运维idden classes this remains undefined. It is not enough to define
bool operator == (const Y& other) const { //stuff}
because the types don't match. How do I solve these problems?
You can force construction by making the no argument constructor private and having a public single int argument constructor in your base class. As long as the base class has some pure virtual methods, then your subclasses must call that constructor.
As for the operator==, try defining
bool operator == (const BaseClass& other) const { .. };
in all of your subclasses. Worst case, you can define a public equals(const BaseClass& other) method that is pure virtual in your base.
EDIT: the forcing constructor thing is not entirely true. What I suggested forces sub classes to call the single argument constructor. They could have a no argument constructor that passes a constant up to the base in constructor.
There's an easy solution.
// Class X
// (... some documentation ...)
//
// ** NOTE: All subclasses of X must have a constructor that takes a single int,
// ** and overload operator==.
class X {
...
For b), you can define virtual bool operator == (const X & other) const = 0
in X.
You can't have const Y & other
as the parameter in the comparison, but Ys will be automatically casted to Xs and then you can use dynamic_cast to see if it's a class that you can compare with.
a - should be possible if you use CRTP and an intermediary, friend, templated subclass that all user code must inherit from. Something like so:
struct X
{
virtual bool compare(X const&) const = 0;
private:
X();
template < typename T >
friend struct client_base; // don't recall the correct code here.
};
template < typename Sub >
struct client_base : X
{
// use boost::concepts to verify Sub has Sub(int)
Sub() : X() {}
};
struct Y : client_base<Y>
{
Y(int);
bool compare(X const& x)
{
if ((Y* other = dynamic_cast<Y*>(x)) && *other == *this) return true;
return false;
}
};
Obviously I've left a lot for you to figure out to make this a complete solution.
a) doesn't have a sense as for me but you can create something
template< typename T >
Base* create( int x )
{
return T::create( x );
}
for b) ask google about "multi methods" implementation in c++
Enforcing to be constructible from an integer does not make any sense: each derived class is free to define its constructors as it wishes. You can however enforce them to pass an integer to the base class... not that it makes much more sense anyway.
The operator==
is also contorted, you can however get the essence of it:
class Base
{
public:
bool operator==(const Base& rhs) const;
bool operator!=(const Base& rhs) const { return !(*this == rhs); }
private:
virtual bool equals(const Base& rhs) const = 0; // will pass only objects
// of the same dynamic type
};
bool Base::operator==(const Base& rhs) const
{
return typeid(*this) == typeid(rhs) && this->equals(rhs);
}
bool Derived::equals(const Base& rhs) const // We KNOW Base is actually a Derived
{
return *this == static_cast<const Derived&>(rhs);
}
You could try and prettify it a bit by using templates and CRTP, but what if Derived
was inherited from ? it would not hold.
精彩评论