从继承的角度理解 C++ 命名空间和使用声明的问题


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,因为它继承了Ai,还是只有命名空间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::iC::A::i,简称为B::iC::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;
}};

最新更新