二义性

自然语言的二义性什么意思

面这个问题.很清楚的说明了自然语言的二义性..

用红墨水写一个“蓝”字,请问,这个字是红字还是蓝字?

可能很少有人意识到,像红字和蓝字这样的词语都存在着二义性。可能是红色的字,也可能是“红”这个字。

二义性定义:如果文法G中的某个句子存在不只一棵语法树,则称该句子是二义性的。如果文法含有二义性的句子,则称该文法是二义性的。

C++中常见的两种二义性问题及其解决方式

--------------------------------一、“倒三角”二义性问题-------------------------------

问题描述:卤煮之所以称之为“倒三角问题”,是因为这一类二义性问题所处的继承体系类似于倒三角形状,如图:

这样,在子类中就存在父类A、B的两份show(),在调用的时候就会出现二义性问题,这种问题该怎么解决呢?

面对问题:


//这里的“倒三角”问题二义性怎么解决?即有两个基类共同派生出一个子类,这两个基类中又同时存在相同的功能的时候
//派生出的子类在调用该功能的时候也会出现二义性问题  这时候该怎么解决?
//解决方法:利用区域限定符(::)  详细解决方案见实验tempt

*/

/*
class grandpa
{
public:
    void show()
    {
        cout<<"This is grandpa\n";
    }
};
class father
{
public:
    void show()
    {
        cout<<"This is father\n";
    }
};
class son:virtual public grandpa,virtual public father
{
public:
    void display()
    {
        cout<<"This is son\n";
    }
};
int main()
{
    son son;
    son.show();
    son.display();
    cout << "Hello world!" << endl;
    return 0;
}

//这里的“倒三角”问题二义性怎么解决?即有两个基类共同派生出一个子类,这两个基类中又同时存在相同的功能的时候
//派生出的子类在调用该功能的时候也会出现二义性问题  这时候该怎么解决?
//解决方法:利用区域限定符(::)  详细解决方案见实验tempt
*/

解决方法:区域限定符(::)

#include <iostream>

using namespace std;
//下面这种情况出现的二义性怎么解决?
class grandpa
{
public:
    void show()
    {
        cout<<"This is grandpa\n";
    }
};
class father
{
public:
    void show()
    {
        cout<<"This is father\n";
    }
};
class son:virtual public grandpa,virtual public father
{
public:
    void display()
    {
        cout<<"This is son\n";
    }
};
int main()
{
    son son;
    son.father::show();//“倒三角”问题出现的二义性利用区域限定符(::)来解决
    son.grandpa::show();
    son.display();
    return 0;

}

-------------------------------------------二、“恐怖菱形”二义性问题---------------------------------------

面对问题:
描述:有最基类A,有A的派生类B、C,又有D同时继承B、C,那么若A中有对象a,那么在派生类B,C中就存在a,又D继承了B,C,那么D中便同时存在B继承A的a和C继承A的a,那么当D的实例调用a的时候就不知道该调用B的a还是C的a,就导致了二义性。

 图示:

 

解决方案:  虚基类、虚继承
教科书上面对C++虚基类的描述玄而又玄,名曰“共享继承”,名曰“各派生类的对象共享基类的的一个拷贝”,其实说白了就是解决多重多级继承造成的二义性问题。例如有基类B,从B派生出C和D,然后类F又同时继承了C和D,现在类F的一个对象里面包含了两个基类B的对象,如果F访问自己的从基类B那里继承过来的的数据成员或者函数成员那么编译器就不知道你指的到底是从C那里继承过来的B对象呢还是从D那里继承过来的B对象。

于是虚基类诞生了,将C和D的继承方式改为虚继承,那么F访问自己从B那里继承过来的成员就不会有二义性问题了,也就是将F对象里的B对象统一为一个,只有一个基类B对象,下面是一段代码说明了对虚基类的使用。

#iclude <iostream>

using namespace std;

class A
{
    public:
    int i;
    void showa(){cout<<"i="<<i<<endl;}
};

class B:virtual public A      //此处采用虚继承
{
    public:
    int j;
};

class C:virtual public A      //此处采用虚继承
{
    public:
    int k;
};

class D:public B,public C
{
    public:
    int m;
};
int main()
{
    A a;
    B b;
    C c;
    a.i=1;
    a.showa();
    b.i=2;
    b.showa();
    c.i=3;
    c.showa();
    D d;
    d.i=4;
    d.showa();
    //cout << "Hello world!" << endl;
    return 0;
}

从这个代码我们可以看出B,C,D从A那里继承过来了i这个变量并且它们之间不会有任何影响,如果B和C不是虚继承方式的,那么d.i=4;就不能编译通过了。 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值