为什么C++中没有通用基类?
从设计的角度来看,为什么在C++中没有母类,而在其他语言中通常是object
?
From a design point of view, why is that, in C++, there is no mother-of-all base-class, what's usually object
in other languages?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
最终裁决可在 Stroustrup 常见问题解答中找到。
简而言之,它不传达任何语义意义。这是有代价的。模板对于容器来说更有用。
The definitive ruling is found in Stroustrup's FAQs.
In short, it doesn't convey any semantic meaning. It will have a cost. Templates are more useful for containers.
让我们首先考虑一下为什么你想要一个基类。我可以想到几个不同的原因:
这是 Smalltalk、Ruby 和 Objective-C 品牌的语言拥有基类的两个充分理由(从技术上讲,Objective-C 并没有真正拥有基类,但出于所有意图和目的,它确实有)。
对于#1,通过在 C++ 中包含模板,无需将所有对象统一在一个接口下的基类。例如:
当您可以通过参数多态性始终保持类型完整性时,这是不必要的!
对于 #2,在 Objective-C 中,内存管理过程是类实现的一部分,并且是从基类继承的,而 C++ 中的内存管理是使用组合而不是继承来执行的。例如,您可以定义一个智能指针包装器,它将对任何类型的对象执行引用计数:
然后,您将调用其包装器中的方法,而不是调用对象本身的方法。这不仅允许更通用的编程:它还允许您分离关注点(因为理想情况下,您的对象应该更关心它应该做什么,而不是在不同情况下应如何管理其内存)。
最后,在像 C++ 这样同时具有基元和实际对象的语言中,拥有基类(每个值的一致接口)的好处就消失了。您有某些不符合该接口的值。为了在这种情况下使用原语,您需要将它们提升为对象(如果您的编译器不会自动执行此操作)。这造成了很多复杂化。
所以,对你的问题的简短回答是:C++ 没有基类,因为通过模板具有参数多态性,它不需要。
Let's first think about why you'd want to have a base-class in the first place. I can think of a few different reasons:
These are the two good reasons that languages of the Smalltalk, Ruby and Objective-C brand have base-classes (technically, Objective-C doesn't really have a base-class, but for all intents and purposes, it does).
For #1, the need for a base-class that unifies all objects under a single interface is obviated by the inclusion of templates in C++. For instance:
is unnecessary, when you can maintain type integrity all the way through by means of parametric polymorphism!
For #2, whereas in Objective-C, memory management procedures are part of a class's implementation, and are inherited from the base class, memory management in C++ is performed using composition rather than inheritance. For instance, you can define a smart pointer wrapper which will perform reference counting on objects of any type:
Then, instead of calling methods on the object itself, you'd be calling methods in its wrapper. This not only allows more generic programming: it also lets you separate concerns (since ideally, your object should be more concerned about what it should do, than how its memory should be managed in different situations).
Lastly, in a language that has both primitives and actual objects like C++, the benefits of having a base-class (a consistent interface for every value) are lost, since then you have certain values which cannot conform to that interface. In order to use primitives in that sort of a situation, you need to lift them into objects (if your compiler won't do it automatically). This creates a lot of complication.
So, the short answer to your question: C++ doesn't have a base-class because, having parametric polymorphism through templates, it doesn't need to.
C++ 变量的主要范例是按值传递,而不是按引用传递。强制所有内容都从根
Object
派生将使按值传递它们本身成为错误。(因为按值接受对象作为参数,根据定义会对其进行切片并删除其灵魂)。
这是不受欢迎的。 C++ 让您思考是否需要值语义或引用语义,从而为您提供选择。这是性能计算中的一件大事。
The dominant paradigm for C++ variables is pass-by-value, not pass-by-ref. Forcing everything to be derived from a root
Object
would make passing them by value an error ipse facto.(Because accepting an Object by value as parameter, would by definition slice it and remove its soul).
This is unwelcome. C++ makes you think about whether you wanted value or reference semantics, giving you the choice. This is a big thing in performance computing.
问题是C++中有这样一种类型!它是
void
。 :-) 任何指针都可以安全地隐式转换为void *
,包括指向基本类型、没有虚表的类和有虚表的类的指针。由于它应该与所有这些类别的对象兼容,因此
void
本身不能包含虚拟方法。如果没有虚函数和 RTTI,则无法从void
获得有关类型的有用信息(它匹配每种类型,因此只能告诉每种类型都正确的内容),但是虚函数和 RTTI 会使事情变得简单类型非常低效,并且阻止 C++ 成为适合直接内存访问等低级编程的语言。所以,有这样的类型。由于该语言的低级性质,它只是提供了非常简约(实际上是空的)界面。 :-)
The problem is that there IS such a type in C++! It is
void
. :-) Any pointer may be safely implicitly cast tovoid *
, including pointers to basic types, classes with no virtual table and classes with virtual table.Since it should be compatible with all those categories of objects,
void
itself can not contain virtual methods. Without virtual functions and RTTI, no useful information on type can be obtained fromvoid
(it matches EVERY type, so can tell only things that are true for EVERY type), but virtual functions and RTTI would make simple types very ineffective and stop C++ from being a language suitable for low-level programming with direct memory access etc.So, there is such type. It just provides very minimalistic (in fact, empty) interface due to low-level nature of the language. :-)
C++ 最初被称为“带有类的 C”。
它是 C 语言的发展,与 C# 等其他一些更现代的语言不同。
而且你不能将 C++ 视为一种语言,而是将其视为语言的基础(是的,我记得 Scott Meyers 的书《Effective C++》)。
C 本身是多种语言、C 编程语言及其预处理器的混合体。
C++ 添加了另一种组合:
类/对象方法
模板
STL
我个人不喜欢某些东西直接从 C 到 C++。枚举功能就是一个例子。 C# 允许开发人员使用它的方式要好得多:它将枚举限制在其自己的范围内,它具有 Count 属性并且很容易迭代。
由于C++想要与C向后兼容,设计者非常宽容地允许C语言整体进入C++(有一些细微的差别,但我不记得你可以使用你自己的C编译器做任何事情)使用 C++ 编译器无法做到)。
C++ was initially called "C with classes".
It is a progression of the C language, unlike some other more modern things like C#.
And you can not see C++ as a language, but as a foundation of languages (Yes, I am remembering the Scott Meyers book Effective C++).
C itself is a mix of languages, the C programming language and its preprocessor.
C++ adds another mix:
the class/objects approach
templates
the STL
I personally don't like some stuff that come directly from C to C++. One example is the enum feature. The way C# allows the developer to use it is way better: it limits the enum in its own scope, it has a Count property and it is easily iterable.
As C++ wanted to be retrocompatible with C, the designer was very permissive to allow the C language to enter in its whole to C++ (there are some subtle differences, but I do not remember any thing that you could do using a C compiler that you could not do using a C++ compiler).
C++ 是一种强类型语言。然而令人费解的是,它在模板专业化的背景下没有通用的对象类型。
模式为例,
以可以实例化为的
现在假设我们希望特定函数具有相同的模式。就像
专门化的实例化
一样,但是遗憾的是,尽管类 T 可以在专门化之前代表任何类型(类或非类),但没有等效的
自动回退
(我使用该语法作为最明显的泛型)在这种情况下,非类型一)可以在专门化之前代表任何非类型模板参数。因此,一般来说,此模式不会从类型模板参数转移到非类型模板参数。
就像 C++ 语言中的许多角落一样,答案可能是“没有委员会成员想到它”。
C++ is a strongly typed language. Yet it is puzzling that it does not have a universal object type in the context of template specialization.
Take, for example, the pattern
which can be instantiated as
Now let's assume that we want the same for a particular function. Like
with the specialized instantiation
But alas, even though class T can stand in for any type (class or not) before specialization, there is no equivalent
auto fallback
(I am using that syntax as the most obvious generic non-type one in this context) that could stand in for any non-type template argument before specialization.So in general this pattern does not transfer from type template arguments to non-type template arguments.
Like with a lot of corners in the C++ language, the answer is likely "no committee member thought of it".