为什么C ++中没有基类?

时间:2011-04-18 00:01:58

标签: c++ language-design

快速问题:从设计的角度来看,为什么在C ++中,没有母语所有的基类,在其他语言中通常是object

6 个答案:

答案 0 :(得分:114)

明确的裁决见Stroustrup's FAQs。 简而言之,它没有传达任何语义含义。这将是一个成本。模板对容器更有用。

  

为什么C ++没有通用类对象?

     
      
  • 我们不需要一个:在大多数情况下,泛型编程提供静态类型安全的替代方案。其他情况使用多重继承处理。

  •   
  • 没有有用的通用类:真正的通用不带有自己的语义。

  •   
  • “普遍”课程鼓励人们对类型和界面进行粗略的思考,并导致过多的运行时检查。

  •   
  • 使用通用基类意味着成本:对象必须被堆分配为多态的;这意味着内存和访问成本。堆对象自然不支持复制语义。堆对象不支持简单的作用域行为(这使资源管理变得复杂)。通用基类鼓励使用dynamic_cast和其他运行时检查。

  •   

答案 1 :(得分:43)

让我们首先想一想为什么你想要首先拥有一个基类。我可以想到几个不同的原因:

  1. 支持可处理任何类型对象的通用操作或集合。
  2. 包括所有对象共有的各种过程(例如内存管理)。
  3. 一切都是对象(没有原语!)。有些语言(比如Objective-C)没有这个,这会让事情变得非常混乱。
  4. 这就是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 ++编译器无法完成的编译器。