C++: 继承一个类是否将其带入命名空间中?

7
这里有一些人为编写的示例代码:

以下是示例代码:

template<typename T> void Do(T arg) { (void)arg->b; }

namespace A {
    struct Foo { int a; };
}

namespace B {
    struct Foo { int b; };
    struct Bar : A::Foo {
        void Blah() { Do((Foo *)0); }
    };
}

使用gcc 4.8.2编译(clang会出现类似的错误):

namespacebug.cpp: In instantiation of ‘void Do(T) [with T = A::Foo*]’:
namespacebug.cpp:10:34:   required from here
namespacebug.cpp:1:39: error: ‘struct A::Foo’ has no member named ‘b’
 template<typename T> void Do(T arg) { (void)arg->b; }
                                       ^

注意在错误中它提到了T = A::Foo,即使在调用处我正在创建一个位于命名空间B内的Foo。如果我删除基类声明(: A::Foo),那么所有内容都会编译通过。
这似乎表明继承自A::Foo会以某种方式将其带入我的命名空间,并将其与我的Foo匹配使用?是哪个C++ "特性"导致了这种情况?
(当然,这个问题可以通过对Foo使用命名空间轻松解决,但这不是问题的关键。)

(void)arg->b; - 这是什么意思? - Ed Heal
2
@EdHeal,我认为那只是为了强制出错。 - StoryTeller - Unslander Monica
@StoryTeller - 那做愚蠢的事情有什么意义呢? - Ed Heal
5
@EdHeal,重点在于展示不同情境下名称查找返回不同结果。 - StoryTeller - Unslander Monica
@StoryTeller - 但是在现实世界中有人使用/编写这种代码吗?我希望不是。它很难维护,对于维护者来说也不容易理解。如果一个人编写了这样的代码,那么软件将来肯定会出问题,如果不是现在就是以后。 - Ed Heal
3
@EdHeal,我同意SO应该引导开发者进行更好的设计,但这个问题是关于语言机制的。例子只应被视为例子,不要过分解读。它将有助于希望了解该特性的未来的SO用户。就像优秀书籍中的糟糕代码一样,会有助于学习。 - StoryTeller - Unslander Monica
2个回答

5
由于注入类名规则,类的名称就像成员一样可见。
9/2
“类名”在其声明的范围内被插入,紧接着看到“类名”。 “类名”也被插入到类本身的范围中;这被称为“注入类名”。 为了进行访问检查,将注入类名视为公共成员名称。
因此,就好像类“A :: Foo”包含一个名为“Foo”的成员,该成员命名为类型“A :: Foo”。由于在“Bar :: Blah()”中查找名称时将基础成员视为优先于命名空间成员,因此查找“Foo”的名称会找到注入类名,该名称命名为“A :: Foo”。

3
继承一个类是否将其带入了命名空间?
有点像。如果在类中查找名称失败,则会在基类中继续查找。
“成员名称查找”还包括查找嵌套类型。在同一节中可以找到以下内容:
[注:在具有类型T的多个基类子对象的情况下,可以明确地找到在基类T中定义的静态成员、嵌套类型或枚举类型。两个基类子对象共享它们的公共虚拟基类的非静态成员子对象。—end note]

1
这是针对成员的。这是一种类型,而不是成员,并将其与基类类型匹配。 - Aardappel
@Aardappel 正确。然而,注入的类名是基类的成员,就像其他成员一样被继承。这就是你可以编写像 struct A { }; struct B : A { }; int main() { B::A(); } 这样的代码的原因。 - user743382
@Aardappel,名称查找还包括嵌套类型。请查看我的更新。 - R Sahu
我想你是对的。虽然很奇怪,因为它似乎违反了命名空间规则。 - Aardappel

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