C++打字和 OOP 子类

发布于 2024-09-01 00:12:51 字数 329 浏览 8 评论 0原文

我有点困惑:

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

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

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

注意:抱歉,如果我问了太多问题,请忽略它们,只关注那些用列表装饰点“标记”的问题:) 另外,这不是我的家庭作业。我是一名业余程序员,拥有使用 OOP 编写脚本语言的技能,但对于 C++ 中的 OOP 键入还比较陌生。

I'm a bit confused:

  • If I have a base class A, and a class B which extends A, can a variable of the type A hold a value of the type B and vice versa?

If yes, why? Aren't they completely different even if B is derived from A? How about type-safety?

  • If this is possible, what things do I have to mind when taking use of this? How would this work out in terms of performance?

Note: Sorry if I asked too many questions, just ignore them and just look out for those "marked" with the list decoration dot :)
Also, this is not my homework. I'm a hobby programmer and have skills in scripting languages with OOP, yet I'm relatively new to OOP typing in C++.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夏尔 2024-09-08 00:12:51

如果你这样做:

B b;
A a = b;

那么你就会得到“切片”。 a 将仅包含 bA 部分。

但您可以拥有引用/指针:

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

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

If you do this:

B b;
A a = b;

then you get "slicing". a will contain just the A part of b.

But you can have references/pointers:

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

In this case, ra and pa just refer/point to the real B object. This is because public inheritance models an IS-A relation. This is easier to understand with more descriptive names. Think of A and Animal and B as Baboon. A Baboon IS-A Animal so by using references/pointers, you can treat a Baboon as it's more generic Animal type.

白况 2024-09-08 00:12:51

指向 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!

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

A pointer or reference to an object of class A can point/refer to an object of class B. That's because if B derives from A, then a B is-a A. Each object of class B has all the member variables and functions of class A, plus those unique to 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!

Usually, this sort of code is used when you want to make use of polymorphic behavior through virtual functions.

﹎☆浅夏丿初晴 2024-09-08 00:12:51

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

Not to be contrary, but performance is not the right question here. If you've decided that you're going to make an OO design, don't sacrifice the correct abstraction for performance concerns. Premature optimization is the root of all evil. Good luck!

羞稚 2024-09-08 00:12:51

A 类型的变量可以保存 B 类型的值(对于“hold”的某些定义,如其他答案所解释的),但绝对不能反之亦然。打破一个标准示例:

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 的特定类型)必须在运行时发生 - 这称为动态调度。对于非虚拟方法,决策可以在编译时发生

A variable of type A can hold a value of type B (for certain definitions of "hold", as other answers explain), but definitely not vice-versa. To break out a standard example:

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

This is legal, because Cat derives from Animal:

Cat c;
Animal& a = c;

This isn't:

Animal a;
Cat& c = a;

This is type-safe because you've defined it to be so; the whole point of inheritance is to allow this sort of thing to happen, so you can go on to call methods on a generic Animal variable without knowing what base class happens to be stored in it. As for the performance question, calling virtual methods is slower because deciding which method will actually be called (Cat::foo() versus Dog::foo(), for example, depending on the particular type of Animal stored in the variable) has to happen at run-time -- this is called dynamic dispatch. With non-virtual methods the decision can happen at compile time

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文