【问题标题】:Dynamic Binding Example in C++C++ 中的动态绑定示例
【发布时间】:2012-03-29 14:33:44
【问题描述】:

这段代码是Objective-C动态绑定的经典例子 [1]:

float total = tareWeight;     // start with weight of empty container
int i, n = [self size];       // n = number of members
for (i = 0; i < n; ++i) {     // loop over each member
    id member = [self at:i];  // get next member
    total += [member weight]; // accumulate weight of contents
}
return total;                 // return total weight to caller

所以,作为一名在这门语言方面有一定经验的程序员,我第一次做 C++ 中的步骤,我想知道:给定,这将如何在 C++ 中实现 它还支持某种后期绑定?

在这个例子中,我们假设每个成员都可以属于任何类,但是 当然,实现weight 方法是必须的。这些天机制 也可以使用类似的协议来强制执行 兼容(然后将member 声明为id&lt;Matter&gt;),但在 一切都能正常工作。

在 C++ 中,创建一个具有所谓虚函数的超类是 唯一的选择?

编辑

澄清一下,上面的代码可以看成是一个容器类方法 它返回其组件的总重量。你事先不知道 容器上的内容,可以是任何对象。你只知道 这些对象响应消息weight。


[1] 面向对象编程,一种进化方法,第二 1991 年版 - Brad J. Cox、Andrew J. Novobilski - 第 4 章第 65 页

【问题讨论】:

  • “用所谓的虚函数创建一个超类是唯一的选择吗?”差不多,是的。你有什么问题?
  • 虚函数的“所谓”是什么?它们是 c++ 中动态绑定的定义——使用的函数在运行时解析。
  • @leftaroundabout 有一个细微的区别:Objective-C 版本使用 implicit 接口 - 它适用于任何响应具有整数返回值的 weight 方法的类,而规范的 C++ 实现要求类通过子类化(可能是抽象的)基类并覆盖其 virtual int weight() 成员函数来实现 explicit 接口。后者要求修改类,除非它已经碰巧实现了接口。
  • 好的,实现将使用虚函数。但是声明member 变量呢?我的意思是,我怎样才能将它声明为一个类并作为另一个类初始化/使用?抱歉,我对 C++ 知之甚少。
  • @sidyll 我不清楚你到底在问什么,因为我根本不在 Objective-c 中工作,但我认为你需要做的是让 member 成为指向基类的指针(超类);当您在此指针上调用虚方法时,会找到适当的方法。这必须用指针来实现,如果你使用对象来代替,你会遇到“对象切片”。我还想指出,您可以研究“访问者模式”来替代在元素类本身中实现所有功能。

标签: c++ objective-c late-binding dynamic-binding


【解决方案1】:

您的成员变量需要是指向weighable 基类的指针。这样的指针可以引用任何派生实例。

由于指针会带来内存泄漏的风险,所以把它做成智能指针是很聪明的。 C++11 有unique_ptr。所以你的课可能看起来像

class heavyContainer {
  std::vector<std::unique_ptr<weighable>> members;
 public:
  float total_weight() {
    float result = tareWeight;
    for(auto& member: members)
      result += member->weight();
    return result;
  }
  ...
};

要使用weighable 的任意派生实例初始化成员,您需要堆分配这些对象。这可能有点棘手,因为没有通用方法来复制基类指针引用的对象。一种方法是使插入函数成为模板:

template<class WeighableDerivedObject>
heavyContainer::insert(const WeighableDerivedObject& obj){
  members.push_back(new WeighableDerivedObject(obj));
}

这可以通过 C++11 移动语义变得更高效。

【讨论】:

  • 谢谢,这说明了很多,而且我发现我还有很多东西要学习——其中一些语法对我来说仍然很困难。使用 Objective-C 中的快速枚举也可以使循环变得更容易,但我只是想保留书中的原始示例(它可以追溯到语言中的这些循环工具之前)。在语言战争下为我辩护:-) Brad Cox 甚至在他的书中说,OOP 和传统编程之间的唯一实质性区别是消息选择机制。这虽然存在于 C++ 中(有点),但过于模糊并带有其他复杂性。
【解决方案2】:

与 C++ 最接近的是具有虚函数的超类。如果您真的关心后期绑定,则使用虚拟功能,尽管在您的示例中不清楚这是否有必要。权重可能只是超类中可公开访问的数据成员。

C++ 中动态绑定的形式是严格地在类层次结构上下。这允许编译器进行一定程度的检查,而不是将其全部留给运行时系统。除非你使用不安全的演员表。

请注意,您确实在 C++ 中获得了多重继承,因此您希望能够使用的类只需继承自这个超类,但也可以继承自其他完全不相关的东西。

【讨论】:

  • 可公开访问的数据成员?听起来不是个好主意,但它可能是一个访问数据成员的公共非虚拟函数。
  • 这在一定程度上是一个品味问题:有些人希望所有数据成员都是私有的,并且需要访问者。有些人认为该规则有例外的余地。
  • 感谢@DRVic。我稍微编辑了这个问题。还有关于多重继承的好处,这在这些情况下很有用。
猜你喜欢
  • 2021-06-20
  • 2015-09-14
  • 2011-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多