views:

121

answers:

7

I want to add a class directly into a new class by avoiding public inheritance. For example I have a class like

class size {
private:
    int width;
    int height;
public:
    void set_width(int w) { width = w; }
    int get_width() { return width; }
    void set_height(int h) { height = h; }
    int get_height() { return height; }
    int get_area() { return width*height; }
};

and simply want to plug in it's functionality into a new class like this

class square : public size { 
    // ...
};

and can write

square s;
s.set_width(10);
s.set_height(20);
cout << "Area of the square: " << s.get_area() << endl;

But this way I'm violating the is-a rule for public inheritance. My square isn't a size it has-a size. So I have to write

class square {
public:
    size its_size;
    // ...
};

But now my original idea of plugging the functionality of size right into square gets lost. I have to write

square s;
s.its_size.set_width(10);
s.its_size.set_height(20);
cout << "Area of the square: " << s.its_size.get_area() << endl;

or add several wrappers for the getters and setters of size into square.

Edit: I have to add: size isn't destined to have a virtual destructor. I don't want to use size and it's descendants polymorphically.

Edit 2: Another example: You want to write a class that provides the same interface as std::list<T> but offers a lot more functionality than a simple free standing function can accomplish. The standard containers shoudn't be subclassed so you have to add a std::list<T> as a member and wrap all publicly provided functions of std::list<T> directly to your new class. That's a lot of repetitive work and error prone.

Question: Is there a possibility to add the interface of size publicly into square without publicly inheriting from size. My square shouldn't be a size but ought to offer the same interface (next to its own parts).

+3  A: 

Why is your interface size? Why not make it a shape or a boundedarea or some such, which describes the interface just as well, and for either of which a square definitely is-a (shape/boundedarea)?

Amber
yes, I think it's a nomenclature problem here. Unless you want to use the size class elsewhere
djeidot
no, it's only an example. I don't want to use size polymorphically. The functionality of size should simply added to square.
phlipsy
please consider my newest edits too. What happens if I want to plug in a std::list<T> into my class?
phlipsy
Then you probably should be using it as a member variable to allow for proper encapsulation - while it's unlikely that `std::list` is going to change, if you ever wanted to use a different base object, or if somehow it *did* change, you wouldn't want to have to modify anything except your one class to make the change.
Amber
+2  A: 

No, there is no such possibility. If you want to reuse a "interface" (this name does not exist officially in C++), you must use inheritance.

But in such a case i dont think that inheritance is a bad idea.

EDIT:

There is no problem in inheriting from std:: containers. Although it doesn't make sense to me, the following code compiles on Visual Studio 2005:

#include <list>

class myclass : public std::list<int>
{
};
RED SOFT ADAIR
If I want to plug in std::list<T> into my class it's simply forbidden. The standard containers aren't supposed to be subclassed
phlipsy
Its legal. I just tried it. See my edited post.
RED SOFT ADAIR
It's legal but not intended, because they haven't virtual destructors. Pointers to base classes won't delete correctly.
phlipsy
+1  A: 

It sounds to me that you want to tell the world that your square implements an interface, namely the size interface.

Normally, an interface in C++ is represented as an abstract base class (which doesn't get around the is-a, unfortunately). One way that you could work around this here would be to make use of duck typing. In this case, implement the functions that size provides on square and forward the calls to the contained size object. Unless your code requires that the object can be converted into an object of type size instead of just requiring the functions to be present, this should work fine.

Timo Geusch
That's right. But what should I do if I have to forward a great amount of public functions? Or if I want to plug in size into many many classes.
phlipsy
In that case I think the pragmatic answer is to either inherit from `size` directly or from a base class that does the forwarding for you and contains size itself. Yes, it probably goes against the OO grain but OTOH you'll end up in copy/paste hell if you don't and try to duplicate the forwarding in every class, especially for a large number of functions.
Timo Geusch
A: 

The square has a size as one of its components, I don't think you are violating any rule by inheriting. So long as the behaviour of those components remain the same (same width, height, area) otherwise you might want to declare them as virtual in the base class in order to be able to override them if necessary.

As Dav said, if the name does really sound odd to you, you can find a better naming convention, but as far as the functionality is concerned, that's inheritance you want, why make the code more difficult to read and use?

You may also check this check this documentation on inheritance to convince you with a similar example.

RedGlyph
A: 

Sounds like you need an 'interface' called 'sizeable'. In that you can define those methods that you want square, and other sizable objects, to implement. Since the calculations will differ depending on shape types I don't think it makes sense to have a size object already defined with an implementation.

Composition could also be used as you stated in your original post if you want to keep size an object with its method implantation. You still may want to change the size object to square_size, something like that. The nomenclature works out too with the has-a relationship.

Holograham
A: 

Why not compose your classes? Let square have a size ivar, and when you call, say, getArea() on the square class, just have it internally call its_size.getArea() and return that value.

jbrennan
Because with size it's simple, forwarding only 5 functions is ok. But what happens if I have to forward 15 functions? Or if I want to plug in size into many objects?
phlipsy
A: 

Using an inheritance here violates the Liskov Substitution Principle, so I would use composition.

In order to access the composed class, I would define wrappers for its member functions if the class is small (has only a few functions, like size), or would use getter/setter to the whole composed object if the class is big.

Igor Oks