【问题标题】:What can be instantiated?可以实例化什么?
【发布时间】:2009-11-16 23:15:02
【问题描述】:

C++ 中可以实例化哪些类型?

我知道下面每个直接创建Foo的单个实例:

Foo bar;
Foo *bizz = new Foo();

但是,内置类型呢?以下是创建两个int 的实例,还是实例使用了错误的词而只是分配了内存?

int bar2;
int *bizz2 = new int;

指针呢?上面的示例是创建了int * 实例,还是只是为int * 分配内存?

是否也会使用像 423.14 这样的文字来创建实例?

我见过这样的论点:如果你不能子类化一个类型,它就不是一个类,如果它不是一个类,它就不能被实例化。这是真的吗?

【问题讨论】:

    标签: c++ oop


    【解决方案1】:

    只要我们谈论 C++,唯一的权威来源就是 ISO 标准。除了类和函数模板之外,它不会使用“实例化”这个词。

    但是,它确实使用了“实例”一词。例如:

    具有自动存储持续时间 (3.7.2) 的每个对象的实例与其块中的每个条目相关联。

    请注意,在 C++ 语言中,int 左值也是一个“对象”:

    C++ 程序中的构造创建、销毁、引用、访问和操作对象。对象是一个存储区域。

    由于new 明确创建了存储区域,因此创建的任何东西都是对象,并且按照规范的先例,可以称为实例。

    【讨论】:

    • 这可能是迄今为止最好的答案。 C++ 标准和通用 OOP 术语之间的差异很有趣。大多数 OOP 程序员可能不会将int x 之类的东西称为int 的实例,也不会将int 称为对象;但无论如何,这样称呼它在技术上是正确的。
    • 是的,Pavel 引用的“实例”在通常的 OOP 意义上根本没有被使用,因为它说的是“对象的实例”,而不是“类型的实例”。我认为它可以替换为“具有...的不同对象”并且意思相同。我推测大多数 OOP 程序员不会将 int 称为对象,因为他们接受过 Java 培训,实际上 int 不是 Object。更纯粹的 OOP 语言不会对内置类型进行例外处理,因此它们的整数是对象。在 Ruby 中,您可以为代表它们的类动态地猴子补丁方法,以使 3.minutes 等于 180。
    【解决方案2】:

    据我所知,您实际上只是在这里询问术语。 C++ 标准唯一真正的区别是 POD 类型和非 POD 类型,其中非 POD 类型具有用户定义的构造函数、成员函数、私有变量等特性,而 POD 类型没有。 intfloat 等基本类型当然是 POD,POD 数组和 POD 的 C-structs 也是如此。

    除了(并与)C++ 重叠,面向对象编程中的“实例”概念通常是指在内存中为对象分配空间,然后使用构造函数对其进行初始化。无论是在堆栈还是堆上,还是在内存中的任何其他位置上完成这一点,在很大程度上都无关紧要。

    但是,C++ 标准似乎将所有数据类型都视为“对象”。例如,在 3.9 中它说:

    "类型T的对象表示 是 N 个 unsigned char 的序列 类型的对象占用的对象 T,其中 N 等于 sizeof(T)..."

    所以基本上,C++ 标准本身的唯一区别是 POD 与非 POD。

    【讨论】:

    • 引用标准很棒。谢谢!看起来是朝着正确方向迈出的一步。
    • 您的声明“像 intfloat 这样的基本类型当然是非 POD,POD 数组和 POD 的 C 结构也是如此。”似乎不正确。您的意思是将“非 POD”替换为“POD”,反之亦然?
    • 对,对不起 - 这是一个错字。我对帖子进行了一些编辑,并修复了这个错误。
    • POD 结构确实有构造函数(就像任何没有明确定义构造函数的结构/类/联合一样)。这些构造函数是“微不足道的”,正如 C++ 规范所称的那样,但它们仍然存在。
    • True:POD 结构具有隐式构造函数。如果你真的定义了一个构造函数,那么这个对象就不再是 POD。
    【解决方案3】:

    在 C++ 中,“实例”和“实例化”仅与类相关联

    但是请注意,这些也是可以具有会话意义的英语单词。 “指针”在英语用法中肯定是一类事物,而指针肯定是该类的一个实例

    但在 c++ 中,“指针”不是类,指针也不是类的实例

    另见 - 针头上有多少天使

    【讨论】:

    • 但是在其他语言(例如 smalltalk)中,一切都是对象,因此您确实会获得整数等实例。
    • “在 C++ 中,'instance' 和 'instantiate' 仅与类相关联”- 来源?
    【解决方案4】:

    “实例”的概念并不是 C++ 真正固有的东西——基本上你有“有构造函数的东西和没有构造函数的东西”。

    所以,所有类型都有大小,例如一个 int 通常是 4 个字节,具有几个 int 的结构将是 8 个字节,依此类推。现在,在该结构上添加一个构造函数,它开始看起来(和行为)像一个类。更具体地说:

    int foo; // <-- 4 bytes, no constructor
    
    struct Foo
    {
      int foo;
      int bar;
    }; // <-- 8 bytes, no constructor
    
    struct Foo
    {
      Foo() : foo(0), bar(0) {}
      int foo;
      int bar;
    }; // <-- 8 bytes, with constructor
    

    现在,这些类型中的任何一种都可以存在于 stackheap 上。当你在 stack 上创建一些东西时,比如“int foo;”上面,在其范围消失后消失(例如在函数调用结束时)。如果你用“新”创建一些东西,它会在 heap 上找到自己的位置来存放在内存中,直到你调用 delete 为止。在这两种情况下,构造函数都会在实例化期间被调用。

    【讨论】:

      【解决方案5】:

      执行“new int”是不寻常的,但它是允许的。您甚至可以将 0 或 1 个参数传递给构造函数。我不确定“new int()”是否意味着它是 0 初始化的(我猜是的),与“new int”不同。

      在堆栈上定义一个值时,通常不称为“分配内存”(尽管理论上它是在堆栈上获取内存,但该值可能只存在于 CPU 寄存器中)。

      文字不一定在程序内存中获得地址; CPU 指令可以直接对数据进行编码(例如,将 42 放入寄存器 B)。可能任意浮点常量都有地址。

      【讨论】:

      • 我主要是在寻找int 和其他内置类型是否可以实例化的答案。我假设,根据其他答案和您的答案,int 有一个构造函数,因此可以有一个实例,对吗?
      • 不,int 没有构造函数。 C++区分POD和非POD类型,其中POD类型可以有构造函数、成员函数、私有成员变量等,非POD类型不能。
      • POD 结构确实有构造函数。他们没有 non-trivial 构造函数。