【问题标题】:Mixing smart pointers to class objects with class objects将指向类对象的智能指针与类对象混合
【发布时间】:2017-08-03 14:31:17
【问题描述】:

我有一个代码,其中一些类通过设计使用工厂函数来生成实际类,而另一些则不使用。许多类都实现了同名的函数,并且这些函数被顺序调用(见下文)。这种设计导致混合了指向对象和对象本身的智能指针。下面的代码是不是设计不好,我应该到处使用智能指针吗?

#include <iostream>
#include <memory>

class A
{
    public:
        void print_name() { std::cout << "A\n"; }
};

class B
{
    public:
        virtual void print_name() = 0;
        static std::unique_ptr<B> factory(const int n);
};

class B1 : public B
{
    public:
        void print_name() { std::cout << "B1\n"; }
};

class B2 : public B
{
    public:
        void print_name() { std::cout << "B2\n"; }
};

std::unique_ptr<B> B::factory(const int n)
{
    if (n == 1)
        return std::make_unique<B1>();
    else if (n == 2)
        return std::make_unique<B2>();
    else
        throw std::runtime_error("Illegal option");
}

int main()
{
    A a;
    std::unique_ptr<B> b1 = B::factory(1);
    std::unique_ptr<B> b2 = B::factory(2);

    // The block below disturbs me because of mixed . and ->
    a.print_name();
    b1->print_name();
    b2->print_name();

    return 0;
}

编辑

我在下面的 cmets 后面的示例中添加了智能指针。

【问题讨论】:

  • 一致的代码更容易理解和维护。
  • 所以您建议也将a 设为指针?
  • 正如 Valentin 下面提到的,原始指针在现代 C++ 代码中确实不受欢迎。在这种情况下,我会使用 std::unique_ptr 。您应该研究智能指针,以确保您了解哪个更适合您。
  • @Sergei,请阅读我对 Valentin 帖子的评论。这不是关于智能指针与普通指针的讨论。

标签: c++ class oop pointers reference


【解决方案1】:

这在我看来是一个合理的设计。在客户端代码中,您将通过基类接口工作。

class Base {};
class A: public Base {};
class B: public Base {};
class B1: public B {};
class B2: public B {};

class Factory {
  std::unique_ptr<Base> create(const int n) {
    // Instantiate a concrete class based on n
    return std::unique_ptr<Base>(new A());
  }
}

【讨论】:

  • 我在您编写答案时编辑了变量名称。现在你的Base 和我的有点混淆。
  • 即使没有共同点,为什么还要从同一个 Base 派生所有类?
  • @Chiel 他们似乎在您的代码中有相同的界面。这创造了一个合理的假设,它们是相关的。
  • 正确命名有助于避免混淆。
  • 我同意。我将变量重命名为与您的答案一致。
【解决方案2】:

通常,如果不需要,您应该避免使用指针。在大多数情况下,诸如返回值优化之类的主题使它们成为可选的。另外,不要使用 C 样式指针。 C++11 引入了 memory-header,其中包含许多有用的智能指针。

是的,我觉得在这样的程序中使用这些指针是一个糟糕的设计决定。

【讨论】:

  • 如果您以代码的形式发布解决方案会很有帮助。我知道智能指针在这里是一个选项,但这根本不会改变问题,因为那样我就会将智能指针混合到对象和对象中。
  • 对不起:错误的分支。 @Chiel 它不会改变任何东西。如果 A、B 和 C 相关并且可以通过相同的接口进行操作 - 最好的选择是拥有一个基类(可能是抽象的)。这将大大简化客户端代码。
  • 有人已经为此发布了一个很好的解决方案。很抱歉没有给出代码示例,但是智能指针在 C++ 中是一个非常流行的话题,并且有很多关于它的文章和代码示例,可以通过快速搜索获得。 @Sergei 是对的。这可能不是关于应该使用智能指针还是原始指针的讨论,而是关于改进代码设计的讨论。在这种情况下,智能指针就是解决方案。要么,要么你听我的建议,使用副本,不要担心。现代编译器已经可以解决这个问题。
【解决方案3】:

除了混合之外,为什么代码会打扰您?你认为什么实际上会因为它而变得糟糕?您认为这种差异真的会损害可读性吗?

是的,调用 print 的行看起来不同,并且这种差异告诉您正在以不同的方式管理对象。

如果开发人员不能同时理解两者,那么将它们设为相同并没有明显的好处。然后 -> 那么你有更大的问题。

我曾在一个代码库中工作,其中几乎所有内容都由共享指针处理以保持一致性,即使有些东西不应该是指针,而且大多数东西并不是真正共享的。应该避免不必要的不​​一致,但在隐藏合法差异的情况下保持一致确实没有帮助。

您的代码对所有指针的一个好处是,由于 a 不是指针,您可以确定 a 不为空。

【讨论】:

  • 您只是将多态性扔出窗外。你最好学习如何利用它来发挥你的优势。此设计不会超出给定示例的范围。
  • 你不知道我对多态性的了解。即使使用多态类,如果在这种情况下 'a' 绝对应该是 A 并且是局部变量,那么值和指针使用的组合也很好。我看到一些人在误解多态性时犯的一个错误是假设如果 2 个类有任何共同的方法名,它们应该共享一个基类。从类名 A、B、C Base 中,无法判断 A 是否应该按原样建模 - 只有当它从 Base 继承时才应该建模,即使这样,如果需要,对象 a 也可以是本地非指针变量。
  • 在这种情况下,每个公共方法怎么样? factory() 并不真正属于该对象。
  • 您也忘记了不需要公共基类的静态多态性。
  • 不,我没有忘记静态多态性,谢谢。
猜你喜欢
  • 2023-02-09
  • 2013-03-27
  • 1970-01-01
  • 1970-01-01
  • 2021-05-18
  • 1970-01-01
  • 2016-09-25
  • 1970-01-01
  • 2012-09-10
相关资源
最近更新 更多