“isa”的技术方面在 c++
从技术角度来看
到底是什么意思,我理解这意味着我的派生类
总是可以转换为基类
,那就是它?我读了一些材料,没有参考任何技术方面的内容,只有哲学!提前致谢
what exactly does it mean from technical point of view
, I understood that it means that my derived class
can always be converted to base class
, that's it? I read some materials without any reference to technical aspects, only philosophy! thanks in advance
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这意味着我的派生类总是可以转换为基类
实际上这意味着比这更好。
int
始终可以转换为float
,但这并不意味着 int “是”float。它只是意味着可以从 int 构造浮点数。同样,您可以拥有可进行转换但没有其他关系的用户定义类。通过继承,派生类的指针或引用始终可以转换为基类的指针或引用[*]。也就是说,派生类的对象可以代替基类的对象。它实际上就是其中之一。如果一个人可以代替脑外科医生,那么他就是脑外科医生。
“是”的一个正式定义是 Barbara Liskov 的替换原则。诚然,这仍然是哲学,但它是非常合理的哲学,它与您如何编写程序直接相关。
在 C++ 中使用继承时必须明确的另一件事是运行时多态性(使用虚拟函数实现)和静态多态性(实际上根本不需要继承)之间的区别。对于非虚函数调用,所调用函数的版本始终是编译器被告知对象具有的类中定义的版本(静态类型)。如果它在派生类中重载,这实际上可能无法正常工作。对于虚拟调用,调用的版本是对象实际所在的类(动态类型)中定义的版本。决定您的目标是这两种“是”中的哪一种至关重要。
[*] 并且该对象可以通过指针有效访问,也就是说。您始终可以使用
reinterpret_cast
强制指针类型,但这不是我在这里的意思。还有一些繁琐的细节 - 如果基类不明确,那么您无法一次性转换指针,但您可以使用几个明确的强制转换显式地完成此操作。如果基类不可访问,那么您可以对其进行转换,但只能使用 C 样式转换,而不是隐式转换。 C 风格的强制转换就像忽略可访问性的static_cast
,而不是像reinterpret_class
。所以你会得到一个工作指针,但希望你也能强烈意识到你正在做一些非常错误的事情;-)it means that my derived class can always be converted to base class
Actually it means better than that.
int
can always be converted tofloat
, but that doesn't mean an int "is a" float. It just means a float can be constructed from an int. Likewise you can have user-defined classes that convert, but have no other relationship.With inheritance, a pointer or reference to the derived class can always be converted to a pointer or reference to the base class[*]. That is to say, an object of the derived class can stand in place of an object of the base class. It actually is one of those things. If a person can stand in for a brain surgeon, then they're a brain surgeon.
One formal definition if "is a" is Barbara Liskov's substitution principle. Which admittedly is still philosophy, but it's very sound philosophy and it relates directly to how you write programs.
The other thing you have to keep straight when using inheritance in C++ is the difference between runtime polymorphism (achieved using
virtual
functions) and static polymorphism (which doesn't actually require inheritance at all). With non-virtual function calls, the version of the function called is always the version defined in the class that the compiler is told the object has (the static type). This might not actually work correctly, if it's overloaded in the derived class. With virtual calls, the version called is the version defined in the class the object actually is (the dynamic type). It's essential to decide which of the two kinds of "is a" you're aiming for.[*] and the object be validly accessible through the pointer, that is. You can always coerce pointer types with
reinterpret_cast
, but that's not what I mean here. And there are some fiddly details - if the base class is ambiguous then you can't convert the pointer in one go, but you can do it explicitly using several unambiguous casts. If the base class is not accessible then you can convert it, but only with a C-style cast, not implicitly. The C-style cast acts like astatic_cast
which ignores accessibility, not like areinterpret_class
. So you get a working pointer, but hopefully also a strong sense that you're doing something very wrong ;-)派生类在给定点 R 处只能转换为可访问且明确的基类。除了 C++ 标准本身之外,不乏引用和其他地方。
再说一次
就 OOAD 原则而言:
我个人推荐 Robert Martin 的文章很好地掌握这一点,尤其是 OCP 原则。对我来说,作者解释这些传奇的 OOAD 指南的清晰度和权威性是无法比拟的。
另请参阅 @Steves 帖子中解释的 LSP
A derived class can be converted to only an accessible and unambiguous base class at a given point R. There is no dearth of references and what other place than the C++ standard itself.
And again
In terms of OOAD principles:
I would personally recommend Robert Martin's articles for getting a good hold on this especially the OCP principle. It is not possible for me to beat the clarity and authority with which the author explains these legendary OOAD guidelines
Also look at LSP as explained in @Steves' post