Adding publicly but inheriting private
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).
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)?
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>
{
};
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.
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.
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.
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.
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.
精彩评论