快速问题:从设计的角度来看,为什么在C ++中,没有母语所有的基类,在其他语言中通常是object
?
答案 0 :(得分:114)
明确的裁决见Stroustrup's FAQs。 简而言之,它没有传达任何语义含义。这将是一个成本。模板对容器更有用。
为什么C ++没有通用类对象?
我们不需要一个:在大多数情况下,泛型编程提供静态类型安全的替代方案。其他情况使用多重继承处理。
没有有用的通用类:真正的通用不带有自己的语义。
“普遍”课程鼓励人们对类型和界面进行粗略的思考,并导致过多的运行时检查。
使用通用基类意味着成本:对象必须被堆分配为多态的;这意味着内存和访问成本。堆对象自然不支持复制语义。堆对象不支持简单的作用域行为(这使资源管理变得复杂)。通用基类鼓励使用dynamic_cast和其他运行时检查。
答案 1 :(得分:43)
让我们首先想一想为什么你想要首先拥有一个基类。我可以想到几个不同的原因:
这就是Smalltalk,Ruby和Objective-C品牌的语言都有基类的两个很好的理由(从技术上讲,Objective-C实际上没有基类,但是对于所有意图和目的,它确实)。
对于#1,通过在C ++中包含模板,可以避免需要一个统一单个接口下所有对象的基类。例如:
void somethingGeneric(Base);
Derived object;
somethingGeneric(object);
是不必要的,当你可以通过参数多态来保持类型的完整性!
template <class T>
void somethingGeneric(T);
Derived object;
somethingGeneric(object);
对于#2,而在Objective-C中,内存管理过程是类实现的一部分,并且是从基类继承的,C ++中的内存管理是使用组合而不是继承来执行的。例如,您可以定义一个智能指针包装器,它将对任何类型的对象执行引用计数:
template <class T>
struct refcounted
{
refcounted(T* object) : _object(object), _count(0) {}
T* operator->() { return _object; }
operator T*() { return _object; }
void retain() { ++_count; }
void release()
{
if (--_count == 0) { delete _object; }
}
private:
T* _object;
int _count;
};
然后,不是在对象本身上调用方法,而是在其包装器中调用方法。这不仅允许更通用的编程:它还允许您分离关注点(理想情况下,您的对象应该更关注它应该做什么,而不是在不同情况下应该如何管理它的内存)。
最后,在具有原语和C ++等实际对象的语言中,拥有基类( 每个 值的一致接口)的好处将丢失从那以后,你有一些不符合那个界面的值。为了在这种情况下使用基元,你需要将它们提升到对象中(如果你的编译器不会自动执行它)。这会造成很多复杂化。
所以,对你的问题的简短回答:C ++没有基类,因为通过模板进行参数多态,它不需要。
答案 2 :(得分:15)
C ++变量的主导范式是按值传递,而不是传递给参数。强制从根Object
派生所有内容会使它们通过值传递错误事实。
(因为通过值接受一个Object作为参数,根据定义将它切成片并移除它的灵魂)。
这是不受欢迎的。 C ++让您考虑是否需要值或引用语义,为您提供选择。这是性能计算中的一件大事。
答案 3 :(得分:6)
问题是C ++中有这样的类型!它是void
。 :-)任何指针都可以安全地隐式转换为void *
,包括指向基本类型的指针,没有虚拟表的类和带有虚拟表的类。
由于它应该与所有这些类别的对象兼容,void
本身不能包含虚方法。如果没有虚函数和RTTI,就无法从void
获取有关类型的有用信息(它匹配每种类型,因此只能告诉每种类型的事情都是真的),但虚函数和RTTI会使简单类型非常无效并阻止C ++成为适合直接内存访问等低级编程的语言。
所以,有这样的类型。由于语言的低级特性,它只提供非常简约(实际上是空的)接口。 : - )
答案 4 :(得分:-2)
C ++是一种强类型语言。然而令人费解的是,它在模板专业化的背景下没有通用对象类型。
例如,采用模式
T
可以实例化为
A<string>.B.A<int>.B.M
现在让我们假设我们想要一个特定的功能相同。像
int
使用专门的实例化
template <class T> class Hook;
template <class ReturnType, class ... ArgTypes>
class Hook<ReturnType (ArgTypes...)>
{
...
ReturnType operator () (ArgTypes... args) { ... }
};
但是,即使T类在专业化之前可以代表任何类型(类或不同类),也没有等效的Hook<decltype(some_function)> ...;
(我使用该语法作为此类中最明显的通用非类型语法context)在专门化之前可以代表任何非类型模板参数。
因此,通常这种模式不会从类型模板参数转移到非类型模板参数。
与C ++语言中的许多角落一样,答案可能是“没有委员会成员想到它”。
答案 5 :(得分:-3)
C ++最初被称为“C with classes”。 它是C语言的进步,不像C#等其他更现代的东西。 而且你不能将C ++看作是一种语言,而是作为语言的基础(是的,我记得Scott Meyers的书“Effective C ++”)。
C本身是语言的混合,C编程语言及其预处理器。
C ++增加了另一种组合:
类/对象方法
模板
STL
我个人不喜欢直接从C到C ++的一些东西。一个例子是枚举功能。 C#允许开发人员使用它的方式更好:它将枚举限制在自己的范围内,它具有Count属性,并且很容易迭代。
由于C ++希望与C语言兼容,因此设计人员非常宽容地允许C语言完全进入C ++(存在一些细微的差别,但我不记得使用C语言可以做的任何事情使用C ++编译器无法完成的编译器。