views:

140

answers:

6

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 overridden 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?

+3  A: 

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.

SB
About the equality operator ==, would this not let me dostuff likeY y; Z z; (where Y and Z inherit from X)When I do (y==z), this test will be allowed.
It should work. Try it and see :)
SB
@user231536 - how could doing such a thing make any sense? If two operands of == are not the same type then they're not equal in any sensible definition of 'equal'.
Noah Roberts
A: 
Noah Roberts
A: 

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++

bb
+2  A: 

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.

Fozi
+2  A: 

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 {
 ...
Seriously. Any design which requires subclasses to perform specific actions is bad design. +1
Billy ONeal
A: 

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.

Matthieu M.