公开添加但继承私有

时间:2009-11-06 12:37:10

标签: c++ class

我希望通过避免公共继承将类直接添加到新类中。例如,我有一个类

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; }
};

并且只是想将它的功能插入到像这样的新类中

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

并且可以写

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

但是这样我违反了公共继承的 is-a 规则。我的square不是size,而有一个 size。所以我必须写

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

但是现在我将size的功能插入square的原始想法丢失了。我必须写

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;

或将size的getter和setter的几个包装器添加到square

编辑:我必须补充:size并非注定要拥有虚拟析构函数。我不想使用size并且它的后代是多态的。

编辑2:另一个例子:您希望编写一个提供与std::list<T>相同的接口的类,但提供的功能远远多于简单的独立功能。标准容器不应该是子类,因此您必须添加std::list<T>作为成员,并将std::list<T>的所有公开提供的函数直接包装到您的新类中。这是很多重复性的工作,容易出错。

问题:是否有可能将size公开的界面添加到 square,而不公开继承size。我的square不应该是size,而应该提供相同的界面(在其自己的部分旁边)。

7 个答案:

答案 0 :(得分:3)

为什么您的界面size?为什么不将它设为shapeboundedarea或其他类似的,它也描述了界面,并且对于其中任何一个正方形是-a (形状/ boundedarea)?

答案 1 :(得分:2)

不,没有这种可能性。如果要重用“接口”(此名称在C ++中不正式存在),则必须使用继承。

但在这种情况下,我不认为继承是一个坏主意。

修改

从std :: containers继承没有问题。虽然它对我没有意义,但以下代码在Visual Studio 2005上编译:

#include <list>

class myclass : public std::list<int>
{
};

答案 2 :(得分:1)

我觉得你想告诉全世界你的square实现了一个接口,即size接口。

通常,C ++中的接口表示为抽象基类(不幸的是,它不会绕过is-a)。解决这个问题的一种方法是使用duck typing。在这种情况下,实现sizesquare上提供的功能,并将调用转发给包含的size对象。除非您的代码要求将对象转换为size类型的对象,而不是仅仅要求函数存在,否则这应该可以正常工作。

答案 3 :(得分:0)

广场的大小是其组成部分之一,我认为你不会通过继承来违反任何规则。只要这些组件的行为保持不变(相同的宽度,高度,面积),否则您可能希望在基类中将它们声明为虚拟,以便能够在必要时覆盖它们。

正如Dav所说,如果这个名字对你来说真的很奇怪,你可以找到一个更好的命名约定,但就功能而言,这是你想要的继承,为什么使代码更难以阅读和使用?

您也可以查看此检查this documentation on inheritance以说服您使用类似的示例。

答案 4 :(得分:0)

听起来你需要一个名为'sizeable'的'界面'。您可以在其中定义要实现的方形和其他相当大的对象的方法。由于计算将根据形状类型而有所不同,我认为使用实现已经定义了一个大小对象是不合理的。

如果您希望通过其方法植入保持尺寸为对象,也可以按照原始帖子中的说明使用合成。您仍然可能希望将size对象更改为square_size,就像这样。命名法也与有关系有关。

答案 5 :(得分:0)

为什么不编写课程?让square有一个size ivar,当您在getArea()课程上致电square时,只需在内部调用its_size.getArea()并返回该值

答案 6 :(得分:0)

这里使用继承违反了Liskov替换原则,所以我会使用合成。

为了访问组合类,如果类很小(只有少量函数,如size),我会为其成员函数定义包装器,或者将getter / setter用于整个组合对象如果班级很大。