如果方法调用以两个冒号开头,这意味着什么?

发布于 2024-09-17 16:47:37 字数 353 浏览 19 评论 0原文

一位同事经常写这样的内容:

::someObject->someMethod(anAttribute, anotherAttribute);

someObject 是一个全局变量。
这两个冒号对我来说似乎很奇怪。没有它们,代码编译并运行得很好。

该同事声称这些冒号使 someObject 显式全局化,从而防止与可能的本地 someObject 混淆。我认为如果已经全局定义了 someObject ,你将无法在本地定义它?

您能否解释一下这些冒号的含义以及它们是否必要?

A coworker routinely writes something like this:

::someObject->someMethod(anAttribute, anotherAttribute);

someObject is a global variable.
Those two colons seem strange to me. The code compiles and runs just fine without them.

The coworker claims that those colons make someObject explicitly global and thus prevent confusion with a possible local someObject. I would think that you would not be able to define someObject locally if it was already defined globally?

Could you shed some light on what those colons mean and whether they are necessary?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

宁愿没拥抱 2024-09-24 16:47:37

你的同事是对的。您确实可以定义一个本地 someObject ,它将隐藏该范围内的全局 someObject

SomeClass* someObject = ...;

// here the global object is visible
someObject->someMethod(anAttribute, anotherAttribute); // calls the global object

void someMethod() {
  SomeClass* someObject = ...;
  // here the local object hides the global
  ::someObject->someMethod(anAttribute, anotherAttribute); // calls the global object
  someObject->someMethod(anAttribute, anotherAttribute);   // calls the local object
}

// here again only the global object is visible
someObject->someMethod(anAttribute, anotherAttribute); // calls the global object

范围可以递归地嵌入其他范围内,因此您可以在全局范围内拥有一个名称空间,命名空间中的类、类中的内部类、内部类中的方法、方法中的块...等等。并且您可以在其中任何一个中具有相同名称的变量/类/方法/...范围。因此,在 C++ 中识别特定名称所指的实体并不是一项简单的任务。它被称为名称查找

简而言之,每当编译器找到一个名称时,它都会从最内部的作用域开始查找该名称。即在someMethod内部,名称someObject与本地定义的对象匹配。 ::someObject 覆盖此默认行为,并使编译器仅在最外层(全局)范围内搜索,因此它会找到全局对象而不是本地对象。

Your coworker is right. You can indeed define a local someObject which would hide the global someObject within that scope:

SomeClass* someObject = ...;

// here the global object is visible
someObject->someMethod(anAttribute, anotherAttribute); // calls the global object

void someMethod() {
  SomeClass* someObject = ...;
  // here the local object hides the global
  ::someObject->someMethod(anAttribute, anotherAttribute); // calls the global object
  someObject->someMethod(anAttribute, anotherAttribute);   // calls the local object
}

// here again only the global object is visible
someObject->someMethod(anAttribute, anotherAttribute); // calls the global object

Scopes can be embedded within other scopes recursively, thus you may have a namespace within global scope, a class within a namespace, an inner class within the class, a method within an inner class, a block within the method... etc. And you may have variables/classes/methods/... of identical names in any of these scopes. So identifying what entity a specific name is referring to is not a trivial task in C++. It is known as name lookup.

In brief, whenever the compiler finds a name, it looks up that name starting from the innermost scope. I.e. inside someMethod, the name someObject is matched by the object defined locally. ::someObject overrides this default behaviour and makes the compiler search only within the outermost (global) scope, thus it finds the global object instead ofthe local.

汹涌人海 2024-09-24 16:47:37

即使有一个全局对象,您也确实可以在本地定义一个对象。这两个变量具有不同的作用域,因此编译器知道两者之间存在差异,并且双冒号可让您引用全局变量。

这也适用于命名空间之外的类;即,要从 Bar::Foo 类中引用 Foo 类,您可以使用 ::Foo 告诉编译器您正在谈论不在命名空间中的类。

下面是一个显示其工作原理的示例:

#include<stdio.h>

int someInt = 4;

int main() {
        int someInt = 5;
        printf("%d", someInt+::someInt);
        return 0;
}

如果编译并运行该代码段,它将输出 9。

You can indeed define a someObject locally even though there is a global one. The two variables have different scope, so the compiler knows there's a difference between the two, and the double colons let you refer to the global one.

This also applies to classes outside of a namespace; i.e., to refer to a class Foo from the class Bar::Foo, you use ::Foo to tell the compiler you are talking about the one that isn't in a namespace.

Here's an example that shows it working:

#include<stdio.h>

int someInt = 4;

int main() {
        int someInt = 5;
        printf("%d", someInt+::someInt);
        return 0;
}

If you compile and run that piece of code, it will output 9.

红尘作伴 2024-09-24 16:47:37

同事声称那些冒号
使 someObject 显式全局化并且
从而防止与可能的混淆
本地某个对象。

是的 - 这意味着该函数可以且只能在全局命名空间中匹配。它使您很明显正在处理全局,并且可以防止意外匹配更本地化的内容(例如本地函数、对象成员、命名空间成员、您正在使用的命名空间中、Koenig 查找匹配等)。

我想你不会
能够在本地定义 someObject 如果
它已经被全局定义了吗?

让它成为一个错误将是一个非常糟糕的主意。假设一个程序员团队决定将一个名为“last_error”的变量添加到他们的命名空间中:他们不必担心命名空间中的现有函数是否对局部变量使用相同的名称。如果将函数从一个名称空间或类复制到另一个名称空间或类,则不必在实现中进行容易出错的标识符替换。

关于 :: 的好处,请考虑:

namespace X
{
    void fn() {
        rip(data, bytes); // MP3 rip this data
    }
}

...然后 fn() 需要快速移动到名称空间 Y...

namespace Y
{
    void rip(const char* message, int exit_code); /* for fatal errors */
    ...
}

...随意复制粘贴到 Y 的内部很容易忽略该日志与 fn 位于命名空间 X 中时使用的相同全局函数不匹配,但是 - 如图所示 - 功能可能明显不同:-)。

您可以将每个名称空间、类/结构和函数视为形成一棵树,其中每个级别都必须具有唯一键(即同一名称空间中没有同名的类),但后代始终彼此独立及其祖先。增加独立变化的自由对于让许多人同时解决一个大问题至关重要。

您能透露一下什么吗?
这些冒号的含义以及它们是否是
有必要吗?

在这种特定用法中,:: 可能并不是绝对必要的。它增加了一点保护,但使稍后将变量移动到更局部的范围变得更加困难 - 尽管这并不那么重要,因为编译器会告诉您在移动 x 后继续引用 ::x 的位置。

The coworker claims that those colons
make someObject explicitly global and
thus prevent confusion with a possible
local someObject.

Yes - it means the function can be, and must only be, matched in the global namespace. It makes it obvious you're dealing with a global, and would prevent accidental matching against something more local (beit function local, an object member, namespace member, in a namespace you're using, a Koenig lookup match etc.).

I would think that you would not be
able to define someObject locally if
it was already defined globally?

It would be a very bad idea to make it an error. Say a team of programmers decides they want to add a variable called "last_error" to their namespace: they shouldn't have to worry if existing functions in the namespace use the same name for a local variable. If you copy a function from one namespace or class to another, you shouldn't have to make error-prone identifier substitutions in the implementation.

Regarding the benefits of ::, consider:

namespace X
{
    void fn() {
        rip(data, bytes); // MP3 rip this data
    }
}

...then fn() needs to be moved quickly into namespace Y...

namespace Y
{
    void rip(const char* message, int exit_code); /* for fatal errors */
    ...
}

...a casual copy-paste into the guts of Y could easily overlook that log won't match the same global function it used to when fn was in namespace X, but - as illustrated - the functionality may differ markedly :-).

You can think of each namespace, class/struct and functions forming a tree, where each level must be uniquely keyed (i.e. no same-named classes in the same namespace), but decendents are always independent of each other and their ancestors. Increasing freedom to vary independently is essential for letting many people work simultaneously on a big problem.

Could you shed some light on what
those colons mean and whether they are
necessary?

In this specific usage, the :: probably isn't strictly necessary. It adds a little protection, but makes it harder to move the variable to a more local scope later - though that's not so important because the compiler will tell you about the places that continue to refer to ::x after x is moved.

身边 2024-09-24 16:47:37

只是对响应中所有其他优点的一个小小的补充。

基本上::在全局命名空间中调用限定名称查找。然而,并不能保证它不会出现问题,特别是在面对不加区别的使用指令时。

所示代码说明了限定名称查找的一个重要属性。这里的重点是搜索全局命名空间中使用 using 指令指定的命名空间。但是,在具有正在搜索的名称的命名空间中使用指令将被跳过。

    namespace Z{
        void f(){cout << 1;}
    }

    namespace Y{
        void f(){cout << 2;}
        using namespace Y;     // This namespace is not searched since 'f' is found in 'Y'
    }

#if 0
    namespace Z{
        void f(){cout << 3;}
        using namespace Y;     // This namespace is not searched since 'f' is found in 'Y'
    }
    using namespace Z;
#endif
    using namespace Y;

    int main(){
        ::f();                 // Prints 2. There is no ambiguity
    }

在所示的代码中,如果启用带有 #if 指令的行,则解析名称“f”时会出现歧义。

Just a minor add on to all other nice points which have come in the response.

Basically :: invokes qualified name lookup in the global namespace. However it is not guaranteed to be problem free especially in the face of indiscriminate using directives.

The code shown illustrates an important property of qualified name lookup. The point here is that namespaces nominated by using directives in the global namspace are searched. However using directives in namespaces that have the name being searched are skipped.

    namespace Z{
        void f(){cout << 1;}
    }

    namespace Y{
        void f(){cout << 2;}
        using namespace Y;     // This namespace is not searched since 'f' is found in 'Y'
    }

#if 0
    namespace Z{
        void f(){cout << 3;}
        using namespace Y;     // This namespace is not searched since 'f' is found in 'Y'
    }
    using namespace Z;
#endif
    using namespace Y;

    int main(){
        ::f();                 // Prints 2. There is no ambiguity
    }

In the code shown, if lines with the #if directive are enabled, there is an ambiguity in resolving the name 'f'.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文