先看这个:
class base
{
public:
int b;
void print() {cout 《 "base" 《 endl;}
};
class derived1 : public base
{
public:
int d1;
};
class derived2 : public base
{
public:
int d2;
};
class grandson : public derived1,public derived2
{
public:
int g;
};
这里,我们让derived1和derived2继承base,再让grandson继承derived1和derived2,我们是想实现一个菱形结构:
我们可以写出主程序:
void main()
{
grandson gs;
// gs.b = 1;
// gs.base::b = 1;
// gs.print();
}
看见我加注释的那三句话了吗?每句都会报错的!为什么那?
因为,想实现棱形结构只是我们的一厢情愿!我们又没告诉编译器,编译器哪有那么聪明!
实际结构是这样的:
所以我们应该这样写main函数:
void main()
{
grandson gs;
gs.derived1::b = 1;
gs.derived2::b = 1;
gs.derived1::print();
gs.derived2::print();
}
可以看到,从基类base继承来的成员b和print()函数在grandson中都有两份,这可不是我们想要的!因为这两个b是一样的,都是从base来的;print()也是!
其实,这个问题很好解决,科学家发明了关键字virtual来解决这个问题:
class base
{
public:
int b;
void print(){cout 《 "base" 《 endl;}
};
class derived1 : virtual public base
{
public:
int d1;
};
class derived2 : virtual public base
{
public:
int d2;
};
class grandson : public derived1,public derived2
{
public:
int g;
};
现在我们可以这样写主函数了:
void main()
{
grandson gs;
gs.b = 1;
gs.base::b = 1;
// gs.derived1::b = 1;
// gs.derived2::b = 1;
gs.print();
// gs.derived1::print();
// gs.derived2::print();
}
现在,grandson的b和print都只有一份了,所以编译器不会再告诉我们“ambiguous”了!
当然,按我加注释那几句那么写也没问题,反正现在b和print()都是各占一份内存空间,不再分derived1和derived2继承过来的,是从他们两个共同从base继承过来的。
请注意,对于base,我们什么也没做,他现在就叫做虚基类,因为derived1和derived2在继承时加了关键字virtual!
在现实世界中这种情况是很多见的,比如公司的临时销售人员,又有销售人员的属性,也有临时人员的属性;还有中国老师上课常用的老师和研究生派生的助教的例子,等等。
总之,你只要记住:当你想实现棱形结构时,请使用virtual!
凡本站注明“稿件来源:新科教育”的所有图文音视频,版权均属新科所有,任何媒体、网站或个人未经本网协议授权不得转或以其他方式复制发表。已获得本站协议
授权的媒体、网站,在下载使用时必须注明“稿件来源:新科教育”,违者本站将依法追究责任。