C和C++中的.和->真的是运算符吗?

5
您可能已经被教授,或者自己学习过,.和->是用于检索结构体(C)或类(C ++)成员的运算符
然而,我怀疑它们是否真的是运算符 - 因为如果它们是运算符,那么它们的输入类型是什么?此外,两侧的标识符是相互依赖的 - 这是例如加号运算符所缺乏的特征。
如果这是正确的 - 那么从语言理论的角度来看,它们仍然被标记为运算符,其形式定义是什么?在实践中,它们被称为运算符的意义是什么?
8个回答

6
你认为可以作为运算符参数传递的类型仅限于语言内部可定义的类型。
我认为任何编译器能够识别的类型都可以作为参数传递,包括内部类型,比如 "identifier"。在其AST表示中,该运算符将有两个参数,这足以允许您定义语义。
另一个观点是,语言理论可能为您的词汇提供一组定义,但并不是唯一的定义。
例如,运算符可能是操作机器的人。这个定义与编程理论无关,但这并不妨碍我在领域特定语言中使用它来表达与机器操作相关的事情。同样,数学中的“运算符”一词的广义定义超出了编程理论的范畴,而这个定义并不会因为使用编程语言而无效。
换句话说 - 如果你不称之为运算符,你会怎么称呼它?
编辑:
澄清一下,我的第一个观点是指用于调用运算符(调用)的语法。这些运算符具有右参数,即标识符 - 成员名称,C++语言无法使用数据类型表示。C++语言确实有成员指针,但它们与成员本身不同 - 就像变量与指向该变量的指针不同一样。
我想这就是问题所指的。这些运算符的右参数具有一种在语言中无法正常表示或操作的类型。
当这个语法映射到重载的 operator-> 函数时会发生什么是另一回事。这个函数不是运算符 - 它只是如何实现运算符的方式。

5
我认为你可以使用"operator"关键字来重载->运算符的事实应该是一个明显的提示。
智能指针经常这样做:
template<class T>
struct myPtr {
    T *operator ->()    { return m_ptr; }

    private:
        T *m_ptr;
};
.不能被重载,但它本身也是一个运算符。

3

嗯...sizeof是一个运算符,它的输入类型是什么?我不认为这个问题在区分运算符和非运算符方面有用。

而且,这是因为在编程语言的上下文中,“运算符”的含义恰好是语言的作者所说的含义。这里有点像刘易斯·卡罗尔。


@Steve314:这样定义一个“函数”(包括sizeof)似乎与运算符的定义没有什么不同 - + 运算符同样可以被称为“函数”。 - caf
@caf - 加号运算符在语法上是中缀的。当然,你可以有前缀运算符,但一旦你开始按字母顺序拼写它们,通常术语(除了特定的C/C++行话)就是“函数”。在sizeof的情况下,甚至还需要强制使用括号,这(在一个模糊的、绝对不是Church所说的意义上)倾向于暗示一个函数。 - user180247
1
@Steve314:只有在 sizeof 操作作用于类型名时才需要使用括号 - 如 int array[10];,那么 sizeof array 是完全有效的。将操作符和函数的差别定义为它是使用字母字符拼写还是不拼写似乎有点牵强。 - caf
@Steve:我在古典教育方面有点薄弱:不得不查一下Cratylus。该死的希腊人!在我们举行大学二年级胡扯会议之前两千年就抢走了它们!无论如何,也许委员会犯了一个错误,但为了与其他C和C ++程序员进行交流,这并不重要。 - dmckee --- ex-moderator kitten
@dmckdee - 我只是通过谷歌搜索引用才了解到Cratylus。 - user180247
显示剩余4条评论

1

谢谢,没错。同样的问题也可以针对例如类型转换、作用域解析等标准视为运算符的内容进行说明。然而,我仍然对一般情况下没有函数原型的运算符感到不舒服。 - shuhalo
3
如我在另一个评论中所说 - 引用权威是一种被广泛认为无效的论证。C++ 标准委员会和定义该语言的专家可能使用不当的措辞。但在这种情况下,他们没有,但仍有空间解释为什么措辞是恰当的,而不仅仅是说“某某人这样说”。 - user180247
7
@Steve314说:不,当你引用一个实际上无法定义答案的权威时,权威论只是一种无效的论点。C++标准规定了什么是C++语言中的运算符,而不管在其他地方运算符是什么或意味着什么。 - jalf
2
@Steve314:在C ++中,“操作符”一词是指特定的内容。因此,判断某个东西是否为C++运算符的唯一方法是查看定义,而这种情况下的定义是标准。这不是对权威的呼吁 - 这确实是一种谬论 - 而是“定义上的呼吁”,这是平庸真实的。你可能会认为规范的作者应该选择另一个术语(尽管我不同意),但你最多能说的就是“C++错误地定义了'operator'”。(如果你接下来从中争辩说'operator'在其他地方的含义相同,则适用权威主义的方法。) - Antal Spector-Zabusky
2
@Antal - 当然,任何实质性的文档都需要其自己特定的术语定义。这很好。但是这里的问题特别涉及编程理论中的正式定义,这些定义并不因为我们谈论一个由一份具有某些特定术语的具体文档定义的特定语言而无效。对于某些问题,对标准的引用是完全有效的,但在我看来,在这种情况下这是毫无意义的。最好解释一下为什么选择这些词汇不是错误或误导性的。 - user180247
显示剩余11条评论

1

C++03标准将两者都称为运算符。

例如:

……在应用于其类类型的表达式的.运算符之后……

如果您不熟悉这个术语,可以使用“标点符号”来代替.


1

在线C标准(n1256):

6.5.2.3 结构体和联合体成员

约束条件

1. 点操作符.的第一个操作数必须是限定或未限定的结构体或联合体类型,第二个操作数必须是该类型的成员。

2. 箭头操作符->的第一个操作数必须是“指向限定或未限定结构体”的指针或“指向限定或未限定联合体”的指针,第二个操作数必须是指向的类型的成员。

它们是运算符,其输入类型由标准指定。


1
你可以重载 -> 运算符:Wikipedia。该页面还指出,你不能重载点运算符。这里有一个 -> 重载的例子here
class String // this is handle
{
  ...
  Stringrep *operator -> () const { return b_; }
  private:
  Stringrep *b_;
}

箭头运算符作用于箭头左侧的值,并返回左侧所“持有”的内容。可以将其类比为智能指针

0

哈哈,我知道人们已经迂回地说过这个问题,但是直接说一下。在C语言中,label->实际上是(*label)的简写。话虽如此,"."是引用结构体元素的运算符。因此,->引用指向结构体的指针中的元素。


在 C 的术语中是这样的,但标签包括 C++。在重载时,有一个与 operator* 分开的 operator->,因此“速记”参数不一定适用。话虽如此,确保速记有效仍然是一个好习惯 - 如果你重载了 operator->operator*,你应该一致地重载它们(并考虑到预期的指针语义)。 - user180247
是的,我在讲C语言方面的问题。然而,在C++中重载->运算符我认为是非常糟糕的做法。 - chacham15
我同意,确实如此。由于智能指针和迭代器通常只实现operator*,因此会出现一些不一致性。如果->只是一个简写 - 总是在有意义时可用,并且不需要operator-> - 它将避免一些麻烦。 - user180247

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接