C++开发中级
1045 浏览 5 years, 11 months
5.2 名称冲突以及歧义基类
版权声明: 转载请注明出处 http://www.codingsoho.com/名称冲突以及歧义基类
多重继承崩溃的场景并不难以想象,下面的示例显示了一些必须予以考虑的边缘情况:
1.歧义名称
如果Dog类以及Bird类都有一个名为eat()
的方法,会发生什么?由于Dog类以及Bird类毫不相干,eat()方法的一个版本无法重写另一个版本—在子类DogBird中这两个方法都存在。
只要客户代码不调用eat()方法,就不会出现问题。尽管有两个版本的eat()。
DogBird类仍然可以正确编译。然而,如果客户代码试图调用DogBird的eat()方法,编译器将报错,指出eat()的调用有歧义。编译器不知道该调用哪个版本。下面的代码存在歧义错误:
class Dog{
public:
virtual void bark(){
cout << "Wolf!" << endl;
}
virtual void eat(){
cout << "The dog has eaten" << endl;
}
};
class Bird{
public:
virtual void chirp(){
cout << "Chirp!" << endl;
}
virtual void eat(){
cout << "The bird has eaten" << endl;
}
};
class DogBird : public Dog, public Bird{};
int main(){
DogBird myConfuseAnimal;
myConfuseAnimal.eat(); // BUG, Ambiguous call to method eat()
}
为了消除歧义,可以显式地将对象向上转型(本质上是向编译器隐藏多余的方法版本),也可以使用消除歧义语法。下面的代码显示了调用eat()方法的Dog版本的两种方案:
static_cast<Dog>(myConfuseAnimal).eat(); // Slices, calling Dog::eat()
myConfuseAnimal.Dog::eat(); // calls Dog::eat()
通过使用与访问父类方法相同的语法(::运算符),子类的方法本身可以显式地将具有相同名称的不同方法消除歧义。例如,DogBird类可以定义自己的eat()方法,从而消除其他代码中的歧义错误。在方法内部,可以判断调用那个父类版本:
class DogBird : public Dog, public Bird{
public:
virtual void eat(){
Dog::eat(); //Explictly call Dog's version of eat()
}
};
另一种引起歧义的情况是从同一个类继承两次。例如,如果出于某种原因Bird从Dog继承,DogBird的代码将无法编译,因为Dog变成了歧义基类。
class Dog(){};
class Bird : public Dog() {};
class DogBird : public Bird, public Dog {}; // BUG! Dog is an ambiguous base class
多数歧义基类的情况或者是由人为的“what-if',示例(如前面的示例)引起的,或者是由于类层次结构的混乱引起的。图中显示了前面示例中的类图表,并指出了歧义。
数据成员也可以引起歧义。如果Dog以及Bird具有同名的数据成员,当客户代码试图访问这个成员是就会发生歧义错误。
2.歧义基类
多个父类本身具有共同的父类是一种很可能出现的情况。例如,可能Bird以及Dog都是Animal类的子类,如下图所示。
C++允许这种类型的类层次结构,尽管仍然存在着名称的歧义。例如,如果Animal类有一个public方法sleep(), DogBird对象无法调用这个方法,因为编译器不知道调用Dog继承的版本还是Bird继承的版本。
使用“菱形”类层次结构的最佳方法是将最顶部的类设置为抽象类
,所有方法都设置为纯虚方法。由于类只声明方法而不提供定义,在基类中没有方法可以调用,因此在这个层次上就没有歧义。
下面的示例实现了菱形类层次结构,其中有一个纯虚方法eat(),每个子类都必须定义这个方法。DogBird类仍然需要显式地说明使用哪个父类的eat()方法,但是Dog以及Bird引起歧义的原因是它们具有相同的方法,而不是因为从同一个类继承。
class Animal{
public:
virtual void eat() = 0;
};
class Dog : public Animal{
public:
virtual void bark(){
cout << "Wolf!" << endl;
}
virtual void eat(){
cout << "The dog has eaten" << endl;
}
};
class Bird : public Animal{
public:
virtual void chirp(){
cout << "Chirp!" << endl;
}
virtual void eat(){
cout << "The bird has eaten" << endl;
}
};
class DogBird : public Dog, public Bird{
public:
virtual void eat(){
Dog::eat();
}
};
虚基类是处理菱形层次结构顶部类的更好方法