C ++:访问对象

时间:2017-06-26 20:13:39

标签: c++ class object subobject

我开始编写更大的对象,其中包含其他对象。 有时,我需要能够从main()函数中从包含它的对象的类外部调用子对象的方法

到目前为止,我学习时使用的是吸气剂和二传手。 这将提供类似下面的代码:

class Object {
public:
    bool Object::SetSubMode(int mode);
    int Object::GetSubMode();
private:
    SubObject subObject;
};

class SubObject {
public:
    bool SubObject::SetMode(int mode);
    int SubObject::GetMode();
private:
    int m_mode(0);
};

bool Object::SetSubMode(int mode) { return subObject.SetMode(mode); }
int Object::GetSubMode() { return subObject.GetMode(); }

bool SubObject::SetMode(int mode) { m_mode = mode; return true; }
int SubObject::GetMode() { return m_mode; }

这感觉非常不理想,迫使我为每个需要从外部访问的方法编写(丑陋)代码。 我希望能够做一些像Object->SubObject->Method(param);

这样简单的事情

我想到了一个简单的解决方案:将子对象作为公共放在我的对象中。 这样我就可以从外部简单地访问它的方法。 问题在于,当我学习面向对象编程时,我被告知除了方法之外公开任何东西都是亵渎神灵,我不想开始采取不良的编码习惯。 我在研究之前遇到的另一个解决方案是在中添加一个指向子对象的公共指针?

如何以一种干净的方式访问子对象的方法?

是否允许/将一个对象放在一个类中作为公共访问其方法的良好做法?如果不这样做怎么办?

非常感谢你对此的帮助。

2 个答案:

答案 0 :(得分:0)

指针和公共成员对象的问题是你刚刚删除了信息隐藏。你的代码现在变得更脆弱了,因为它所有人都知道"您已经实现了具有4个对象Wheel成员的对象Car。而不是调用隐藏详细信息的Car函数:

Car->SetRPM(200);  // hiding

你想直接开始旋转车轮:

Car.wheel_1.SetRPM(200);  // not hiding! and brittle!
Car.wheel_2.SetRPM(200);

如果你改变班级的内部怎么办?现在可能会破坏上述内容并需要更改为:

Car.wheel[0].SetRPM(200);  // not hiding!
Car.wheel[1].SetRPM(200);

此外,对于您的汽车,您可以说SetRPM(),并且班级确定它是前轮驱动,后轮驱动还是全轮驱动。如果您直接与车轮成员交谈,则不再隐藏实施细节。

有时您确实需要直接访问类的成员,但创建该类的一个目标是封装和隐藏调用者的实现细节。

请注意,您可以使用Set和Get操作来更新类中的多个成员数据,但理想情况下,这些操作对于Car本身而非特定成员对象有意义。

答案 1 :(得分:0)

  

有人告诉我,除了方法之外公开任何东西都是亵渎神灵

像这样的毯子声明是危险的;你必须考虑每种风格的利弊,但公开成员的彻底禁令对IMO来说是一个坏主意。

拥有公共成员的主要问题是它暴露了可能更好隐藏的实现细节。例如,假设您正在编写一些库:

struct A {
    struct B {
        void foo() {...}
    };
    B b;
};

A a;
a.b.foo();

现在几年后你决定要根据上下文改变A的行为;也许你想让它在测试环境中以不同的方式运行,也许你想从不同的数据源加载等等。哎呀,也许你只是决定成员b的名称不够描述。但由于b是公开的,因此您无法在不破坏客户端代码的情况下更改A的行为。

struct A {
    struct B {
        void foo() {...}
    };
    struct C {
        void foo() {...}
    };
    B b;
    C c;
};

A a;
a.c.foo(); // Uh oh, everywhere that uses b needs to change!

现在,如果你让A包装实现:

class A {
public:
    foo() { 
        if (TESTING) {
            b.foo();
        } else {
            c.foo();
        }
private:
    struct B {
        void foo() {...}
    };
    struct C {
        void foo() {...}
    };
    B b;
    C c;
};

A a;
a.foo(); // I don't care how foo is implemented, it just works

(这不是一个完美的例子,但你明白了。)

当然,这里的缺点是它需要很多额外的样板,就像你已经注意到的那样。基本上,问题是“您是否希望将来实施细节发生变化,如果是这样,现在添加样板或者稍后重构每次调用会花费更多吗?”如果您正在编写外部用户使用的库,那么“重构每个调用”将变为“破坏所有客户端代码并强制他们重构”,这将使很多人非常沮丧。 / p>

当然,不是为SubObject中的每个函数编写转发函数,而只需为subObject添加一个getter:

const SubObject& getSubObject() { return subObject; }

// ...

object.getSubObject().setMode(0);

它遇到了一些与上述相同的问题,虽然它更易于解决,因为SubObject接口不一定与实现相关联。

所有这一切,我认为公共成员肯定是正确的选择。例如,简单的结构,其主要目的是充当另一个函数的输入,或者只是获得从A点到B点的数据包。有时候,所有样板都是过度的。