当前位置: 首页 > 知识库问答 >
问题:

标准中没有“隐式此参数”之类的东西吗?

黄锋
2023-03-14

最近,我问了一个问题,其中一个答案是:

标准中没有“隐式此参数”这样的东西。该标准称之为“隐式对象参数”。

然后有人评论说:

标准中没有“隐式此参数”之类的东西。“似乎是错误的。来自expr.call#4:“如果函数是非静态成员函数,则函数的this参数应使用指向调用对象的指针初始化,就像通过显式类型转换一样进行转换。”

看到上述评论,我认为答案在技术上是不正确的,因为答案说“标准中没有“隐含此参数”这样的东西。”而标准明确谈到了这个参数。

那么,如何进一步解释这一点(双关语)?我的意思是,标准似乎在这个参数的上下文中区分了非静态成员函数和构造函数。例如,该标准规定,对于非静态成员函数,该函数的参数应使用指向调用对象的指针初始化,就像通过显式类型转换一样。但标准对施工人员的要求不同。那么,为什么标准会做出这种区分呢?我的意思是,为什么标准没有规定构造函数也有一个由传递的参数初始化的参数,就像非静态成员函数一样。这再次引出了一个更深层次的问题,即如果构造函数中没有与非静态成员函数不同的This参数,那么我们如何能够在构造函数中使用This参数。例如,我们知道我们可以编写-

最初,通过阅读这里的答案,我认为隐式参数是一个实现细节。但在阅读expr之后。调用#4它似乎不是一个实现细节。

共有2个答案

殷宾白
2023-03-14

以下是本C17标准草案的引文(粗体表示强调,并回答问题,是我的):

…第16页

然而,我应该补充一点,引用的段落似乎不存在于后来的标准草案中。事实上,该(后来的)标准似乎在类似的条款中使用了短语“隐式对象参数”。

所以,也许你应该在你的问题中添加一个特定的版本标签:c 17或c 20,因为这个术语的使用(或不使用)似乎存在分歧。

请注意,上述引文是该标准草案中唯一出现的短语“隐含此参数”。

此外,请注意,我链接的两个文件都只是各自标准的草案版本,并且都附带了此警告性免责条款:

注:这是一份早期草案。众所周知,它是不完整和不正确的,并且有很多格式错误。

翁翰
2023-03-14

如果您认为这是某种隐式参数,请键入以下代码:

#include <iostream>

struct SimpleThing {
    int xyzzy;
    SimpleThing(): xyzzy(42) {}
    void print(int plugh, const int twisty) {
        std::cout << xyzzy << '\n';
        std::cout << plugh << '\n';
        std::cout << twisty << '\n';
        xyzzy = 0;
        plugh = 0;
        twisty = 0;
        this = 0;
    }
};

int main() {
    SimpleThing thing;
    thing.print(7, 99);
}

然后检查您得到的错误:

prog.cpp: In member function ‘void SimpleThing::print(int, int)’:
prog.cpp:12:16: error: assignment of read-only parameter ‘twisty’
   12 |         twisty = 0;
      |         ~~~~~~~^~~
prog.cpp:13:16: error: lvalue required as left operand of assignment
   13 |         this = 0;
      |                ^

请注意,前两个赋值之所以有效,是因为它们是可修改的变量。第三个失败了,因为它当然是(不可修改的)const

尝试分配给此的操作看起来不像是任何类型的“无法写入某种类型的变量”诊断,因为它实际上不是。

此关键字是非静态成员函数(和构造函数/析构函数)中的一个特殊标记,它被转换为正在处理的对象的地址。虽然它可以作为隐藏参数传递,但这在很大程度上是一个实现细节,标准本身并不关心。

C 20标准中的控制部分在[class.this]中:

在非静态成员函数的主体中,关键字this是一个prvalue,其值是为其调用函数的对象的地址。

在那里(整个部分)没有提到这是调用的某种隐藏参数。

而且,关于你关于为什么非静态成员函数和构造函数之间存在区别的问题,我认为这种区别在任何一种情况下都不涉及this的存在,而是与this类型的限定有关。它在构造函数中的存在是不可否认的,正如[class.ctor]所述:

在构建对象期间,如果通过不是直接或间接从构造函数的this指针获取的glvalue访问对象或其任何子对象的值,则将不指定由此获取的对象或子对象的值。

换句话说,我看到了你的报价:

如果该函数是非静态成员函数,则该函数的this参数将使用指向调用对象的指针初始化,就像通过显式类型转换一样进行转换。

由于只指定了此的限定,构造函数不需要这些限定。

与其他成员函数一样,没有讨论构造函数的cv限定转换,因为您实际上无法创建cv限定构造函数。如果您的构造函数不允许设置任何成员变量,那么它将毫无用处,例如:-)

虽然可以使用构造函数创建cv限定的对象,但构造函数本身不是cv限定的。这将在本课程的末尾介绍:

不得声明构造函数和析构函数const易失性const易失性。[注意:但是,可以调用这些函数来创建和销毁具有cv限定类型的对象-结束说明]

以及进一步的内容:

可以为常量对象、易失性对象或易失性对象调用构造函数<代码>常量和易失性语义不应用于正在构造的对象。它们在大多数派生对象的构造函数结束时生效。

老实说,我认为WG21最好进行下一次迭代,并用一个根本没有提到参数的短语(如“thethisproperty”)来代替“函数的这个参数”。

 类似资料:
  • 问题内容: 我正在使用CURSOR进行逐行操作。 我想知道为什么不能并行执行此操作,因为行操作是完全隔离的,只能将一些行插入到另一个表中,并且每一行都有自己的ID分配,因此不存在发生冲突的明显可能性。 我想知道是否有一种方法可以在纯SQL中并行化它? 问题答案: 这通常是通过队列来实现的:选择“待办事项”项并将其放入队列,同时队列读取器(处理线程)将“待办事项”项出队并逐一处理。将表用作队列是一种

  • 我正在学习C语言的课程。我从标准中看到了以下语句: 在重载解析期间,类X的非静态cv限定成员函数被视为一个函数,如果它没有ref限定符或具有左值ref限定符,则该函数将左值引用类型的隐式参数带到cv限定X。否则(如果它有rvalue ref限定符),它将被视为一个函数,将rvalue reference类型的隐式参数作为cv限定的X。 上述语句似乎暗示,对于类的限定非静态成员函数,类的限定非静态成

  • 问题内容: 我正在尝试像这样计算折线的面积 后来我注意到dbgeometry无效的错误的原因我尝试了ms sql 2012中的代码也给了我错误,但是当我尝试那样的时候 多数民众赞成在SQL工作我的问题是有没有使几何在.net有效的谢谢 问题答案: 我同意Bojan,除非您使用的是实体框架? SqlGeometry对象具有MakeValid()函数,因此,使用您的示例,可以在DbGeography和

  • 我只是在尝试内部类,遇到了这个想法,即拥有本地但静态的内部类…好吧,我在静态方法中制作了一个内部类…就这么简单…这是我做的例子 这不会给出任何编译错误。 我知道如何访问静态方法m。但是我想知道是否有办法从外部类访问本地类 LocalStatic.好吧,根据我的理解,我们无法访问方法内部的东西,对吧?因此,我无法从类外部访问LocalStatic或该本地类内的任何方法或属性,只想确保..

  • 关于非静态成员函数,请参见 常量、volatile和ref限定成员函数 其中提到: 非静态成员函数可以不使用ref限定符,也可以使用左值ref限定符(标记 no ref-限定符:隐式对象参数具有引用cv限定X的左值类型,并且还允许绑定右值隐式对象参数 左值引用限定符:隐式对象参数具有引用cv限定X的左值类型 rvalue ref限定符:隐式对象参数的类型rvalue reference指向cv限定

  • 问题内容: 如下表 我正在按如下方式汇总表格 我需要为每个组添加最长的名称()-我该如何处理? 预期产量 问题答案: 您可以使用方便地检索每个组中名称最长的乘客。 在每个GROUP BY组中选择第一行? 但是我看不到将它(或任何其他简单的方法)与您的原始查询合并在一个方法中的任何方法。我建议加入两个单独的子查询: 在join子句中方便地仅输出的一个实例,因此您可以在外部简单地使用。 如果可以为NU