【问题标题】:C++ Typing and OOP child classesC++ 类型和 OOP 子类
【发布时间】:2010-05-11 20:54:38
【问题描述】:

我有点困惑:

  • 如果我有一个基类 A 和一个扩展 A 的 B 类,A 类型的变量是否可以保存 B 类型的值,反之亦然?

如果是,为什么?即使 B 从 A 派生,它们不是完全不同吗?类型安全如何?

  • 如果可以的话,使用它时我需要注意什么? 这在性能方面会如何发挥作用?

注意:对不起,如果我问了太多问题,请忽略它们并注意那些带有列表装饰点的“标记”:) 另外,这不是我的作业。我是一名业余程序员,拥有使用 OOP 编写脚本语言的技能,但我对 C++ 中的 OOP 输入相对较新。

【问题讨论】:

  • 或许可以提供一些代码作为例子:)
  • 为什么?我现在没有具体的例子。子类“与父类具有相同类型”的规则应该是通用的,还是?
  • 没有具体的例子是你感到困惑的原因。编写一些代码,它会帮助您解决所有问题。

标签: c++ oop typing


【解决方案1】:

如果你这样做:

B b;
A a = b;

然后你得到“切片”。 a 将仅包含bA 部分。

但是你可以有引用/指针:

B b;
A &ra = b;
A *pa = &b;

在这种情况下,rapa 只是引用/指向真正的 B 对象。这是因为公共继承对 IS-A 关系建模。使用更具描述性的名称更容易理解。将AAnimalB 视为BaboonBaboon IS-A Animal 所以通过使用引用/指针,您可以将 Baboon 视为更通用的 Animal 类型。

【讨论】:

  • 您能解释一下如何以及为什么使用指针吗?为什么 C++ 不会因为打字错误而大声疾呼?我的意思是 A != B,或者?
  • AB 是类型,而不是对象(与许多其他类型是对象的语言不同)。使用指针,A* 可以引用从 A 派生的任何内容,并且虚函数将正确转发到派生类实现。例如。 Animal* animal = new Baboon(); animal->Eat(); animal->Sleep(); 将调用 Baboon 类的 Eat 和 Sleep 方法,如果它们是虚拟的(在 Animal 中)并在 Baboon 中被覆盖。 OTOH,如果您执行Animal a = Baboon();,则会创建一个狒狒,但随后切片,您将得到一个有效的动物,其中不包含狒狒的任何额外内容。
【解决方案2】:

指向A 类对象的指针引用 可以指向/引用B 类对象。这是因为如果B 派生自A,那么B is-a AB 类的每个对象都具有 A 类的所有成员变量和函数,以及 B 独有的那些。

class A
{
   public:
      virtual ~A();
      void foo();
};

class B : public A
{
   public:
      void bar();
};

A * a = new B;
a->foo(); // perfectly valid, B inherits foo() from A
//a->bar(); // compile-time error, bar() is only defined in B
delete a; // make sure A has a virtual destructor!

通常,当您想通过虚函数利用多态行为时,会使用此类代码。

【讨论】:

    【解决方案3】:

    并非相反,但性能问题在这里不是正确的问题。如果您已决定要进行 OO 设计,请不要为了性能问题而牺牲正确的抽象。过早的优化是万恶之源。祝你好运!

    【讨论】:

      【解决方案4】:

      A 类型的变量可以保存 B 类型的值(对于“持有”的某些定义,正如其他答案所解释的那样),但反之亦然。举个标准例子:

      class Animal {};
      class Dog : public Animal {};
      class Cat : public Animal {};
      

      这是合法的,因为Cat 派生自Animal

      Cat c;
      Animal& a = c;
      

      这不是:

      Animal a;
      Cat& c = a;
      

      这是类型安全的,因为您已将其定义为这样;继承的全部意义在于允许这种事情发生,因此您可以继续调用泛型 Animal 变量上的方法,而无需知道其中存储了哪个基类。至于性能问题,调用虚方法比较慢,因为必须在运行时决定实际调用哪个方法(例如Cat::foo()Dog::foo(),取决于存储在变量中的Animal 的特定类型) -time -- 这称为动态调度。对于非虚拟方法,决策可以在编译时发生

      【讨论】:

      • 在 C++ 中,您分配给的变量必须是一个引用(您的代码会编译,但不会像您期望的那样运行)。代码应为Cat c; Animal& a = c;Animal a; Cat& c = a;。查看其他答案。
      • 这可能是合法的,但它不是很有用。正如 Ken 所说,使用引用(或指针)。
      猜你喜欢
      • 1970-01-01
      • 2016-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-09
      相关资源
      最近更新 更多