【问题标题】:Can you solve this circular dependency problem in C++?你能用 C++ 解决这个循环依赖问题吗?
【发布时间】:2011-09-27 13:52:52
【问题描述】:

有一个带有 clone() 函数的 Object 类,它可以抛出 CloneNotSupportedException* 并被声明为这样。 CloneNotSupportedException 派生自 Exception,Exception 派生自 Object。

继承需要完整的类型,我们有两个,所以很明显我们不能打破循环依赖。成员指针和指针参数是不完整类型的内容,但这对于 throw 声明来说似乎是不够的,即使我们抛出指针也是如此。

类定义与实现分开,使用前向声明,到处都是指针。这还不够。

有没有办法打破这种依赖关系,或者这在 C++ 中是不可能的?

【问题讨论】:

  • 跟着我重复。 “C++ 不是 Java”。 “C++ 也不是 C#”。 “C++ 不是 Java”。 “我是认真的,C++ 不是 Java”。 C++ 没有通用的基类,这是一件好事。它有适当的复制构造函数,所以你不需要弄乱克隆函数,它也不需要需要巨大的继承层次结构。而且,当然,您几乎不应该在 C++ 中使用指针(或动态分配的对象)。请购买好的 C++ 教科书,并尝试学习该语言,而不是在 .cpp 文件中编写 Java。
  • 如何有效地抛出一个指针?帮自己一个忙,让您的异常类派生自 std::exception 并通过 const-reference 捕获。
  • 我在 C++ 中遇到的异常的主要循环是,当您为异常消息定义字符串载体类时(这样构造异常对象就不会抛出,而不是愚蠢的标准库设计) ,那么字符串载体类的一些操作可能需要抛出异常......我还没有找到任何令人满意的答案。有一些变通方法,但它们感觉非常不自然,非常做作,不好。
  • @Frigo:你完全可以选择你自己的,我永远不会剥夺语言这样做的能力。这并不意味着不可能做得更好。 OOP 并不是所有问题的解决方案——通用和函数式编程在许多情况下提供了非常出色的解决方案——例如,C++ 标准库的容器和算法。在 C++ 中,我们没有对象切片的问题,因为它很容易通过不混合值类型和继承来避免,我们为此提供了智能指针。大多数时候,当您需要动态的、可定制的行为时,您会使用容器。
  • @Frigo:哦,在 C++ 社区中,我们通常将诸如工厂和观察者之类的模式视为不支持正确范式来实际解决问题的语言的拐杖,而且它们很少用于高质量的 C++ 代码,因为我们只是不需要它们。例如,观察者模式只是对 Java 不支持函数作为数据这一事实的一种破解,而在 C++ 中我们有函数对象。

标签: c++ class inheritance header dependencies


【解决方案1】:

我不是 C++ 大师...但这是一个(也是唯一一个)我想抛出异常以外的东西的情况...你可以抛出一个值类型,例如整数。我很高兴 C++ 语言设计者有很好的意识来禁止抛出指针......这会造成严重破坏。

【讨论】:

  • 他们没有。不,它不会。事实上,堆栈分配的异常在嵌套的 try...catch 块和析构函数中的抛出方面存在问题。干扰堆栈展开或类似的事情。
  • @Frigo:“或者类似的东西”?也许你可以详细说明一下?因为显然,“正常”的 C++ 权威都没有意识到这个问题,并且一致建议 not 抛出动态分配的异常。也许你应该告诉 Stroustrup 他的错误?
【解决方案2】:

跳过异常说明,没用。

class Object {
    virtual Object* clone() = 0;
    virtual ~Object() {}
};

完成。

顺便说一句,你的设计听起来完全错误,我不能不评论它。

【讨论】:

  • 是的,我就是这样做的,我没有看到其他解决方案。
  • clone方法不应该是const吗?
【解决方案3】:
#include <memory>
#ifndef NDEBUG
  #include <typeinfo>
#endif
#include <cassert>

class Object {
public:
  typedef std::unique_ptr<Object> Ptr;  // C++0x. Use auto_ptr in 03.

  virtual ~Object() { }

  Ptr clone() const {
    Ptr obj = cloneImpl();
    assert( typeid(*obj) == typeid(*this) );
    return obj;
  }

private:
  virtual Ptr cloneImpl() const = 0;
};

只需按值抛出异常并通过const&amp; 捕获它。如果你在cloneImplthrow 你的CloneNotSupportedException 异常,它将传播给调用者,他们可以在那里处理它。

【讨论】:

  • 我会说“在 03 中使用 auto_ptr”,而不是“在 03 中使用 boost::unique_ptr”。
猜你喜欢
  • 2021-09-17
  • 2019-02-23
  • 1970-01-01
  • 1970-01-01
  • 2013-02-04
  • 2017-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多