面试题答案
一键面试C++命名空间防止命名冲突的原理
- 作用域分隔:命名空间定义了一个作用域。不同命名空间中的标识符相互独立,例如:
namespace A {
int num = 10;
}
namespace B {
int num = 20;
}
这里A::num
和B::num
是不同的变量,不会冲突。
2. 显式限定:在使用命名空间中的标识符时,需要通过命名空间名加::
来显式限定,如A::num
,这明确指出了使用的是哪个命名空间中的num
,避免了混淆。
3. 局部覆盖全局:在局部作用域内可以定义与命名空间中同名的标识符,此时局部标识符会覆盖命名空间中的标识符,进一步减少命名冲突的可能性,例如:
namespace Global {
int num = 10;
}
int main() {
int num = 20;
std::cout << num << std::endl; // 输出20,局部num覆盖了Global::num
std::cout << Global::num << std::endl; // 输出10,显式访问Global命名空间中的num
return 0;
}
菱形继承问题描述
- 问题场景:假设有一个基类
Base
,两个派生类Derived1
和Derived2
都继承自Base
,然后又有一个FinalDerived
类同时继承自Derived1
和Derived2
。这样的继承结构形成一个菱形。
class Base {
public:
int data;
};
class Derived1 : public Base {};
class Derived2 : public Base {};
class FinalDerived : public Derived1, public Derived2 {};
- 问题表现:在
FinalDerived
类中会存在两份Base
类的成员(data
),这会导致数据冗余和访问歧义。例如当访问data
时,编译器不知道应该访问从Derived1
继承来的data
还是从Derived2
继承来的data
。
虚继承解决菱形继承问题
- 原理:通过虚继承,在继承体系中,无论从哪个路径继承过来,最终派生类都只会包含一份基类的成员。在上述例子中,修改继承方式为虚继承:
class Base {
public:
int data;
};
class Derived1 : virtual public Base {};
class Derived2 : virtual public Base {};
class FinalDerived : public Derived1, public Derived2 {};
- 效果:此时
FinalDerived
类中只会有一份Base
类的data
成员,消除了数据冗余和访问歧义。虚继承通过在中间派生类(Derived1
和Derived2
)中设置虚基表指针,在最终派生类(FinalDerived
)构建时,根据虚基表指针来确保只初始化一份基类数据。