【问题标题】:Strategy on how to share parameters between an object and one of its members关于如何在对象及其成员之一之间共享参数的策略
【发布时间】:2014-10-25 20:58:40
【问题描述】:

我想问在对象及其成员之一之间共享参数的“最佳”方式是什么。我试图更好地解释我的问题:我有一个需要定义特定 a 参数的 A 类:

class A
{
public:
  A(int);
  ~A();
private:
  int ParameterA;
  ...
}

我还有第二个类 B,它包含一个类 A 的对象作为其成员,并且需要定义另一个参数:

class B
{
public:
  B(int);
  ~B();
private:
  A  MemberA;
  int ParameterB;
  ...
}

现在我的问题是:如果 ParameterA 和 ParameterB 始终相等,那么“最佳”(干净)策略是什么?

我想到了三种可能

  1. 第一个选项是保存相同值的两个副本 与上面代码中的名称不同。这在我看来相当 “危险”,它会迫使我总是检查这两个值 是相等的。
  2. 将 ParameterA 声明为公共,以便 B 类可以访问它
  3. 定义一个 get 函数,以便 B 类可以使用 get 函数访问 ParameterA

还有其他(更好/标准)的方法来处理这种情况吗?我应该遵循什么方法?

【问题讨论】:

  • 听说过关键字friend吗?看到这个链接cplusplus.com/doc/tutorial/inheritance
  • 需求是什么? B 类是否必须具有另一个不同的参数,该参数始终等于“MemberA”中的参数,或者您只需要从 B 访问“MemberA”值的选项?
  • 好吧,如果他们是平等的。你主要关心的是什么?你认为你必须保护这个案子。你必须确保这种关系永远不会改变吗?例如,如果此值是一种 ID,并且两个对象都是相对于另一个对象创建的,则可以使用静态 const 值对其进行初始化。
  • 这有点太抽象,无法准确回答。看来,在这三种可能之中,第三种是最好的一种。如果您的要求更明确,也许其他一些替代方案可能会更好地解决问题。
  • @Alex:是的,我想确保这种关系永远不会改变,但我不能使用 const 值,因为在执行期间应该可以更改 ParameterA(和 ParameterB)。

标签: c++ parameter-passing


【解决方案1】:

您可以将 ParameterA 声明为引用,并将其初始化为引用 ParameterB。

class A
{
public:
  A(int& val) : ParameterA(val) {}
  ~A(){}

private:
  int& ParameterA;
};

class B
{
public:
  B(int val) : ParameterB(val), MemberA(ParameterB) {}
 ~B(){}

private:
  int ParameterB;
  A  MemberA;
};

【讨论】:

  • 威斯布鲁克不错,我喜欢!但我有一个必然的问题:使用你的解决方案,是否可以创建 A 类的“独立”对象,我的意思是 A 类的对象,它们不是任何其他对象的成员?
  • 不错。 'MemberA(ParameterB)' 会这样做,因为您无缘无故地调用 A 的复制构造函数。
  • @user265732 谢谢你是对的,我现在更新了代码。
  • 这是一个有效的解决方案,但它确实有它的缺点。引用成员变量限制了您可以对类执行的操作(例如,它们不可赋值),AB 的生命周期现在取决于外部参数的生命周期。
【解决方案2】:

您对让两个变量始终保持相同值的危险的直觉是正确的:这至少是代码异味,应该避免。

直接的解决方案是继承:

class A {
    public:
        A(int a) : parameterA(a) {}
    protected:
        int parameterA;
};

class B : public A {
    public:
        B(int a) : A(a) {}
};

当然,这个解决方案是否可取取决于上下文,但它应该始终是第一个被评估的。

【讨论】:

  • 我认为 OP 有充分的理由希望 B 包含 A
  • @ChrisDrew 好吧,它确实包含A - 通过继承。
  • 不,在你的设计中B is-an A,这是非常不同的。您可能是对的,也许 OP 可以将他们的设计从组合更改为继承。
  • 感谢@cmaster 我的程序我不能从 A 派生 B 但它很有趣
  • @ChrisDrew 逻辑上BA,这是真的。但是内存中发生了什么?有一个类B 的对象包含类A 的一个子对象,它恰好是B 中的第一个对象。 IE。与定义class B { public: A myBase; }; 完全相同的内存布局。唯一的区别在于用于访问A 子对象的语法。
【解决方案3】:

“最佳”方式可能取决于AB 的使用方式。

在您的选择中,如果可以的话,我会避免使用 1 和 2,但我认为 3 可能是一个合理的选择,除非您确实不想公开参数。如果你想保持参数私有,你可以让B成为A的朋友。

另一种选择是从A 中获取参数的所有权。您可以在类外定义参数(可能在另一个类内)并将引用或指针传递给BA

更灵活的方法可能是使用共享指针,但在实践中您可能不需要这种灵活性。通过使用shared_ptr,您不会像引用那样限制您可以对类执行的操作,并且它不会将AB 的生命周期与外部对象的生命周期联系起来。如果您愿意,可以轻松地自行创建一个自包含的A

#include <memory>

using SharedInt = std::shared_ptr<int>;

class A {
public:
  A(SharedInt parameter) : parameter_(parameter) {}
private:
  SharedInt parameter_;
};

class B {
public:
  B(SharedInt parameter) : a_(parameter), parameter_(parameter) {} 
private:
  A  a_;
  SharedInt parameter_;
};  

int main() {
  auto b = B(std::make_shared<int>(3));
  auto a = A(std::make_shared<int>(7));
}

但我可能会倾向于先采用更具限制性的设计,并且仅在需要时才使用共享指针。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 1970-01-01
    • 2017-03-02
    • 1970-01-01
    • 2017-03-28
    • 2019-02-12
    • 1970-01-01
    相关资源
    最近更新 更多