struct A { int i; };
struct B: A {};
struct C: A {};
struct D: B, C {
using B::i;
void f() {
i = 0;
}
};
似乎我指定使用 A from B 中的 i,但编译器说
错误:“A”是“D”的不明确基数
说实话,我不太明白
using B::i
是做什么的。据我所知,它将 i
从命名空间 B
带到了命名空间 D
。但是,命名空间 B
是否包含 i
,因为它从 i
继承了 A
,还是只有命名空间 A
包含 i
?如果是后者,为什么
//A, B, C is same with above
struct D: B, C {
void f() {
B::i = 0;
}
};
这样编译就没有问题了?
正如您所看到的,我对类继承方面的命名空间的整个概念感到困惑。谁能解释一下命名空间、继承等规则如何与这些示例一起工作?
using B::i
在那里没有用,因为 i
中没有 B
。它对于函数解析很有用。 i = 0;
是this->i = 0;
。由于多重继承,this->i = 0;
要么是static_cast<B*>(this)->i = 0;
,要么是static_cast<C*>(this)->i = 0;
,这会导致歧义。
换句话说,
using B::i
将名称i
带到了类D
的直接范围内,并且没有解决歧义。
有用的示例
using
:
struct A { void f(); };
struct D: A {
void f(int) { f(); } // error: no matching function for call to 'D::f()'
};
struct A { void f(); };
struct D: A {
using A::f;
void f(int) { f(); } // ok
};
关键字
using
根据上下文有多种含义。 C++ 类作用域在名称解析方面是一个命名空间,但并不完全像一个命名空间——这一点值得注意。在类作用域中使用声明与继承相关,而继承不是命名空间功能。另一方面,类作用域不能通过以后的声明来扩展,而命名空间可以。
命名空间范围中的
using
语句如果在命名空间上使用,则可以是 using-directive,对于命名空间成员以及类型别名和别名模板声明,可以是 using-declaration。在 C++20 中,它可用于枚举。
类作用域中的using
是一个using-declaration,它引用派生类定义中的基类成员的名称。这可能允许机会访问模式,例如将基类的受保护成员公开为派生类的公共成员。如果派生类已包含具有相同名称、参数列表和限定条件的成员,则派生类成员将隐藏或覆盖从基类引入的成员。 如果
using-declaration 引用正在定义的类的直接基类的构造函数(例如使用 C::C
),则该基类的所有构造函数都变得可见。显然,它所引用的名称应该是明确的,但您的示例中并非如此。 D 类包含 A 类两次,一次作为 B 类的基类,一次作为 C 类的基类。它们的完全限定名称为
B::A::i
和
C::A::i
,缩写为
B::i
和
C::i
。现在有一个问题:您的声明中哪些必须隐藏,哪些必须根据上述内容公开?
C::A::i
是一个不同的名称,因此
B::i
允许与其冲突。除此之外,由于所有访问权限都默认为
public
,类范围内的任何 using 声明都是多余的。如果
using
位于代码块范围内,则其含义与命名空间 using-declaration 相同。
void f() {
B::i = 0;
}
将与相同
void f() {
using B::i;
i = 0;
}
假设 B 是一个命名空间。 B 不是命名空间,第二种情况的格式不正确。 QED,类作用域并不完全是命名空间。
struct A { int i; };
struct B: A { void f() {
i = 0;
}};