struct A { int i; };
struct B: A {};
struct C: A {};
struct D: B, C {
using B::i;
void f() {
i = 0;
}
};
似乎我指定从 A 从 B 使用 i,但编译器说
错误:"A"是"D"的模糊基数
老实说,我真的不明白using B::i
是做什么的。据我所知,它带来了i
从命名空间B
,到命名空间D
。但是命名空间B
包含i
,因为它继承了A
i
,还是只有命名空间A
包含i
?如果是后者,为什么
//A, B, C is same with above
struct D: B, C {
void f() {
B::i = 0;
}
};
这只是编译没有问题?
如您所见,我混淆了类继承方面的命名空间的整个概念。谁能解释命名空间、继承等规则如何与这些示例一起工作?
using B::i
在那里没有用,因为B
中没有i
。它对于函数解析很有用。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 指令(如果在命名空间上使用)、命名空间成员的using声明以及类型别名和别名模板声明。在 C++20 中,它可以用于枚举。
类作用域中的using
是一个using 声明,它将基类成员的名称引用到派生类定义中。这可能允许偶然访问模式,例如将基类的受保护成员公开为派生的公共成员。如果派生类已包含具有相同名称、参数列表和限定条件的成员,则派生类成员将隐藏或重写从基类引入的成员。
如果using-声明引用正在定义的类的直接基的构造函数(例如使用C::C
),则该基的所有构造函数都可见。
显然,为此,它引用的名称应该是明确的,而在您的示例中并非如此。D类包含A类两次,一次作为B类的基础,一次作为C类的基础.这些完全限定的名称将被B::A::i
和C::A::i
,简称为B::i
和C::i
。现在有一个问题:根据上面所说的,你的陈述中哪些必须隐藏,哪一个暴露了?C::A::i
是一个不同的名称,因此允许B::i
与之冲突。除此之外,由于您的所有访问权限都默认为public
,类范围中的任何使用声明都是多余的。
如果using
在代码块范围内,则它与命名空间使用声明具有相同的含义。
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;
}};