Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 将函数调用转发给成员是错误的做法吗?_C++_Oop - Fatal编程技术网

C++ 将函数调用转发给成员是错误的做法吗?

C++ 将函数调用转发给成员是错误的做法吗?,c++,oop,C++,Oop,在我最近编写的代码中,我被迫直接访问对象的成员以调用其函数,然而,这样做感觉是错误的,因为这似乎违反了封装和Demeter定律。然而,我能想到的唯一好的选择是在类中为我可能要调用的成员的每个函数编写我自己的函数,这将是非常乏味和冗余的。例如: class Object { public: void setNum(int x) { num = x; } private: int num; };

在我最近编写的代码中,我被迫直接访问对象的成员以调用其函数,然而,这样做感觉是错误的,因为这似乎违反了封装和Demeter定律。然而,我能想到的唯一好的选择是在类中为我可能要调用的成员的每个函数编写我自己的函数,这将是非常乏味和冗余的。例如:

class Object
{
    public:
        void setNum(int x)
        {
            num = x;
        }

    private:
        int num;
};

class Object2
{
    public:
        Object obj;
};

int main()
{
    Object2 obj2;
    obj2.obj.setNum(5);
}
vs

Object2
中的
setNum
的调用被转发到
Object
中的相同函数。这样的设计被认为是不好的做法吗?直接访问
obj
是否更好

我也可以让
Object2
Object
继承,但在这种情况下,我将要继承的类不是设计为基类的,它会将受保护的成员暴露给
Object2
,并且似乎不适合开始,因为它不是is-a关系,最好是组合

我的具体情况:我正在使用SFML制作一个游戏,有一个类
Ship
,当然需要一个精灵来代表它。任何时候我想设置或获取飞船的位置、旋转等,我必须直接访问它的精灵,或者在
飞船
中编写一个冗余转发功能。问题是,做这两件事中的任何一件似乎都像是一种代码气味:要么违反封装和德米特定律,要么编写冗余代码

这里的最佳实践是什么?我是否对编写简单的转发函数过于挑剔?或者在这种情况下,直接访问
Ship
的精灵真的没有错吗


这个问题:事实上正是我要问的,然而,两个答案都没有给出一个好的解决方案。一个没有得到宽恕,显然封装性很差,另一个只是使用了一个getter,它似乎是一种安慰剂(如果有的话),没有人回答我的主要问题,即什么是最优雅和可接受的解决方案?

什么解决方案是最好的,这在很大程度上取决于封装的基本语义。您需要尽可能地解耦代码。我将通过以下示例对此进行描述:

  • 你有一个船级,它有一个精灵。您可能需要分离游戏逻辑和渲染。因此,Ships对渲染的了解是,它有一个处理它的Sprite对象。因此,在这种情况下,你是分开的责任,这是好的。所以简单的getter是一个很好的解决方案
  • 但如果绝对坐标和旋转必须存储在一个精灵中,那么事情就会发生变化:游戏逻辑通常需要两个,所以它们必须在船和精灵内部一致地设置。实现这一点的最佳方法是使船舶的“设置位置”和“设置旋转”方法也设置精灵的位置和旋转。通过这种方式,您可以简化与船一起工作的代码,而牺牲了船的复杂性。考虑到那艘船是从几个地方操纵的,这是值得的。注意:出于渲染目的,您可能仍然希望通过getter公开Sprite。你可能想阻止除船之外的任何人设置精灵的位置和旋转,如果这不会使你的代码膨胀太多的话
  • 让我们假设Ship类主要用于渲染。在这种情况下,您可能希望对使用精灵进行图形处理的外部类进行隐藏(因为如果您更改渲染引擎,则无需重写渲染代码以外的任何内容即可)。在这种情况下,您需要通过Ship代理所有对精灵的setPosition和setRotation调用,以隐藏精灵的存在
  • 在这些情况下,都不使用继承,因为继承意味着子代是其祖先的变体。你可以说战列舰是战舰的变种。但船不是精灵的变种,它们太不一样了,意味着不同的东西


    所以:如果封装的类太具体,不应该在外部可见,或者必须与主对象一致操作,那么编写一组代理方法是一个很好的解决方案。否则这些方法只会使代码膨胀,最好提供一种获取嵌套对象的方法。但在这种情况下,我会选择getter方法,而不是公共属性。

    尽管经典的javanese oop学派会这么想,但永远不要忘记,同样干燥(不要重复自己)也被认为是一种好的做法

    尽管OOP只是C++编程支持的众多编程范例之一,但自从第一个汇编程序获得宏之后,WAR就是所有编程的精髓,这在OOP发明家甚至离自己父母的思想和愿望很远之前就已经成立了。 尽管我的经历不公平。。。如果尊重良好的oop实践迫使您编写重复代码的无用样板,那么这意味着

    • 您所使用的语言根本不符合您想要达到的目的,无法正确支持范例或
    • OOP因您试图达到的目的而中断。而C++中的机会是OOP真的是一个破碎的范例。
    对于您的具体问题,委托(该模式通常是这样命名的)在以下情况下是有意义的:

    • 它的授权方式可以改变或改变
    • 委托将隐藏成员接口的一部分
    在您的例子中,您有一个函数,该函数调用可从固定成员访问的固定方法

    这是只针对这个特定的示例,还是在您的实现中,设计总是这样

    如果是这样,委托就不会增加语义值,如果不是将
    a.b.m()
    减少为
    a.m()
    。如果你写的超过。。。让我们假设三个“不做任何事只是转发”函数,这是在浪费时间

    如果b有50个方法,而您只将其中的5个方法授权为私有,那么它将生成p
    class Object
    {
        public:
            void setNum(int x)
            {
                num = x;
            }
    
        private:
            int num;
    };
    
    class Object2
    {
        public:
            void setNum(int x)
            {
                obj.setNum(x);
            }
    
        private:
            Object obj;
    };
    
    int main()
    {
        Object2 obj2;
        obj2.setNum(5);
    }