二義性和C++消除二義性

1.二義性

       二義性的定義是:“如果文法G中的某個句子存在不只一棵語法樹,則稱該句子是二義性的。如果文法含有二義性的句子,則稱該文法是二義性的。”(該定義來自於百度百科)用通俗的話講,如果一句話或者一個符號具有兩種以上的解釋和含義,就說明該話或者符號具有二義性。二義性意味着含義不清和不明確。

       在計算機語言中,如果語言具有二義性,必須消除二義性,才能使程序正常運行。 

2.C++消除二義性

       C++中消除二義性的過程主要包括:1)重載消除二義性;2)和C語言混編消除二義性;3)多繼承消除二義性。

1)重載消除二義性

       重載是C++等面嚮對象語言區別於C語言等純面向過程語言的主要特性之一(隨不是面嚮對象語言的三大特性之一)。泛型編程依賴於重載;作爲靜態多態的特性也依賴於重載。

       重載之所以能成功,是因爲C++通過C++編譯器,把同名函數轉爲不同的函數。也就是說,重載的同名函數,最終還是不同的函數。

       C++編譯器在編譯的時候,編譯的規則如下:把同名函數,如void test() 和  void test(int),分別改爲test()或_test 和 test(int) 或_test_int。       

void test(); //在編譯器中改爲test() 或 _test
void test(int); //在編譯器中改爲test(int) 或 _test_int

       這種改名方法,讓C++可以重載同名函數。

       順便說一下重載的意義:

       1)C++是一種強類型的語言,C++要保證類型的強制性;

       2)C++是一種面嚮對象語言,面嚮對象語言要使語言和抽象設計更加符合,和人類實際語言更加貼切;

       3)基於上面兩個原則,重載纔會存在。

2)C++和C混編消除二義性

        C++全部兼容了C語言的所有特性,C++是C語言的超集。但C++和C語言混編的時候,會出現各種問題。因爲C語言本身不支持重載和多態,C語言的函數不存在改名或者始終是一個函數。這就會造成一個問題,如果C程序和C++混編,存在二義性問題。

       嚴格來說,C和C++混編的二義性,不是C程序造成的,而是C++對原來的純C函數進行了改名。改名以後,原來的C程序找不到原來的函數,就會出現問題。

       爲了避免該類問題,C++和C程序混編的時候,採用的方法是:C程序編譯的時候,採用C語言的規則,並讓C++編譯器知道這部分程序是C語言的,並用C方法對C程序進行編譯。

       使用方法爲:使用extern "C"方法,讓程序明白採用了C函數。通用規則如下;

        

#ifdef __cplusplus
extern "C" {
#endif

.......



#ifdef __cplusplus
}
#endif

3)多繼承消除二義性

       C++支持多重繼承,多重繼承帶來了便利,也帶來了各種麻煩。(與愚蠢的C++(自嘲語,畢竟我靠C++喫飯這麼長時間)相比,JAVA就避免了多重繼承這個特性,並避免了這個麻煩)

       C++的多重繼承問題,最主要體現爲菱形繼承。即基類被多個衍生類繼承,多個衍生類被同一個子類繼承。這會繼承的子類最後出問題,即某個實體的含義不清楚。

       菱形繼承圖示如下:

         

      這樣的多重繼承,在最終類D裏,會無法確定成員的含義。

      爲了讓大家理解多重繼承的二義性,舉個二義性的樣例:

     

class Grand
{
public:
    Grand();
    ~Grand();

    void fun();
};

class FatherA: public Grand
{
public:
    FatherA();
    ~FatherA();
};

class FatherB: public Grand
{
public:
    FatherB();
    ~FatherB();
};

class Son: public FatherA, public FatherB
{
public:
    Son();
    ~Son();
};

int main(int argc, char *argv[])
{
    Son s;
    s.fun(); //二義性,因爲不能確切屬於哪個成員

    return 0;
}

       爲了消除該二義性,方法如下:

       1)多重繼承採用虛繼承;

       2)採用 類名稱::函數,即作用域加功能方法。

4.推廣

       二義性問題其實在實踐中廣泛存在,並不僅僅屬於C++和編程。這個問題屬於任何領域。在工程中,消除任何意義的二義性,顯然是一個工程師都應該做的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章