将类视为第一类对象

问题描述 投票:0回答:7

我正在阅读 GoF 书,在原型部分的开头我读到了以下内容:

此福利主要适用于 像 C++ 这样的语言不处理 类作为第一类对象。

我从未使用过 C++,但我确实对 OO 编程有很好的理解,但是,这对我来说没有任何意义。任何人都可以详细说明这一点(我已经使用\使用:C、Python、Java、SQL,如果有帮助的话。)

c++ oop prototype design-patterns
7个回答
9
投票

要使类成为第一类对象,语言需要支持诸如允许函数将类(而不是实例)作为参数、能够在容器中保存类以及能够从函数返回类等功能。

对于具有一流类的语言的示例,请考虑 Java。 任何对象都是其类的实例。 该类本身就是 java.lang.Class.

的实例

8
投票

对于其他人,这是完整的引用:

“减少子类化。工厂方法 (107)经常产生一个层次结构 与以下并行的创建者类 产品类别层次结构。原型 模式可让您克隆原型 而不是要求工厂方法 制作一个新对象。因此你不 根本需要一个 Creator 类层次结构。 此福利主要适用于 像 C++ 这样的语言不处理 类作为第一类对象。 这样做的语言,例如 Smalltalk 和 目标C,获得较少的利益, 因为你总是可以使用一个类 对象作为创造者。类对象 这些已经像原型一样 语言。”-GoF,第 120 页。

正如史蒂夫所说的那样

我发现这一点很微妙 可能会理解为暗示 类的/实例/不是 处理 C++ 中的第一类对象。 如果GoF用的同样的话出现了 在不太正式的场合,他们可能 我们本来打算/实例/而不是 比类。区别可能不 对/你/来说似乎很微妙。 /我/然而, 确实需要考虑一下。

我确实相信区别在于 重要的。如果我没记错的话,有 与编译的 C++ 相比没有任何要求 程序保留任何工件 对象所属的类 所创造的可以被重建。哦, 使用 Java 术语来说,没有 /类/对象。


4
投票

在 Java 中,每个类本身就是一个对象,派生自 java.lang.Class,它允许您从程序内访问有关该类及其方法等的信息。 C++ 不是那样的;类(而不是其对象)在运行时实际上无法访问。有一个名为 RTTI(运行时类型信息)的工具可以让您按照这些思路做一些事情,但它非常有限,而且我相信会带来性能成本。


3
投票

你已经使用过Python,这是一门一流的语言。您可以将类传递给函数,将其存储在列表中等。在下面的示例中,函数 new_instance() 返回它所传递的类的新实例。

class Klass1:
    pass

class Klass2:
    pass

def new_instance(k):
    return k()

instance_k1 = new_instance(Klass1)
instance_k2 = new_instance(Klass2)

print type(instance_k1), instance_k1.__class__
print type(instance_k2), instance_k2.__class__

2
投票

C# 和 Java 程序可以知道自己的类,因为 .NET 和 Java 运行时都提供 反射,一般来说,它可以让程序获得有关其自身结构的信息(在 .NET 和 Java 中,这种结构恰好是就课程而言)。

如果不依赖运行时环境,您就无法进行反射,因为程序本身无法自我感知*。但是,如果程序的执行由运行时管理,则程序可以从运行时获取有关其自身的信息。由于 C++ 被编译为本机非托管代码,因此您无法在 C++** 中进行反射。

...

* 嗯,程序没有理由不能读取自己的机器代码并“尝试得出结论”。但我认为这是没有人愿意做的事情。

** 不严格准确。使用可怕的基于宏的黑客,只要你的类层次结构有一个根,你就可以实现类似于反射的东西。 MFC 就是一个例子。


2
投票

模板元编程为 C++ 提供了更多玩类的方法,但说实话,我认为当前的系统并不允许人们进行所有可能想做的操作(主要是,没有标准的方法来发现所有可用的方法)到一个类或对象)。 这不是疏忽,而是设计使然。


0
投票

可以带有 P2996,即 “C++26 的反射”

这样,一种新的语法将允许将类型带入值域,因此人们将能够创建一个类型数组,如§3.3中所示:

constexpr std::array types = {^int, ^float, ^double};

可以循环获取其中每一个的大小:

constexpr std::array sizes = []{
  std::array<std::size_t, types.size()> r;
  std::views::transform(types, r.begin(), std::meta::size_of);
  return r;
}();

本文展示了许多其他示例,每个示例都带有编译器资源管理器的链接。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.