c++多态性测试代码中遇到了类型限定符不兼容
PHP中文网
PHP中文网 2017-04-17 13:20:14
0
3
445


编程菜鸟,在学习c++多态性的过程中,写了这样的测试代码,这里会有类型限定符不兼容。
当我在抽象基类的函数声明后添加上const后,就不会出现类型不兼容,这是为什么?

PHP中文网
PHP中文网

认证0级讲师

全部回覆(3)
Ty80

const限定的變數以及其引用只能呼叫const限定的成員函數
const限定代表變數的值不會改變,而要想不改變變數的值則只能呼叫const修飾的成員函數

小葫芦

你的問題其實與多態無關,要解答你這個問題需要兩個方面的知識點。

1. 成員函數的this指標

首先,類別的成員函數內要存取類別的成員,需要透過this指標存取(名稱不衝突時可省略),透過一個物件呼叫成員函數的時候會將物件本身透過this指標傳遞給成員函數。例如:

class A {
public:
    explicit A(int xx = 0) : x(xx) {}
    int get() { return x; }
    void set(int xx) { x = xx; }
private:
    int x;
};

int main() {
    A a;
    a.set(10);  // a.x = 10
    int i = a.get();  // i = 10
}

為什麼我能在a.get()函數裡存取物件a的成員x?就是透過這個this指針。在透過a呼叫a.get()的時候,編譯器會把物件a的位址賦值給this指針,這裡的this指標的型別是A *const。而在get()函數內,return x;這個語句其實相當於return this->x;,這樣我們就能夠透過a.get()來存取物件a的成員x了。

同理,為什麼a.set(10);能夠把物件a的成員x賦值成10?也是透過this指針。 x = xx;就相當於this->x = xx;

以上兩種情況下,由於x的解析不可能出現歧義,所以this指標可以省略。但是,如果我想在成員函數set的參數裡使用與成員x相同的變數名稱該怎麼辦?依然透過this指針進行區分。我們可以把成員函數set的定義修改如下:

A::void set(int x) { this->x = x; }

這裡的this指標就不能省略了,否則的話,寫成x = x;就會出現歧義,編譯器無法解析x到底是函數的參數還是物件的成員。

2. const成員函數

考慮一個情況,在前面的例子中,我們的對象a是一個非常量對象,如果我們想使用類別A聲明一個常數對象怎麼辦?例如

int main() {
    const int ci = 10;
    int i = ci;
    const A ca(5);  // ca.x = 5
    int j = ca.get();  // 编译错误
}

對於內建類型,可以直接定義常數ci,並且使用它的值。那對於我們自己定義的類別A,我們也可以用相同的方法定義常數ca,透過ca.get()取得物件a的成員x的值。

但是,在使用成員函數取得它的資料成員x的值的時候,我們實際上仍然透過this指標來存取成員x,問題是,此時this指標不是const A *const型,而是A *const類型。我們知道,不可以透過非常量的指標來存取常數的內容,即

const int ci = 5;
int *p = &ci;         // 错误
const int *cp = &ci;  // 正确

那麼如何透過this指標來存取成員x呢?我們需要想個辦法讓this指標變成const A *const型。辦法就是,在類別的成員函數宣告末尾加上const關鍵字,這樣就表示該成員函數是 const成員函數,而函數內this指標是常數型別。舉例來說,我們可以重載get()方法:

int A::get() const { return x; }

此時,

int j = ca.get();  // j = 5

就會正常運作了。

應用

具體到你的問題來說,

當我在抽象基底類別的函數宣告後面加上const後,就不會出現型別不相容,這是為什麼?

store_file()函數內,其參數img_file是一個常數參考類型,想要透過一個常數物件呼叫成員函數,就需要這個物件的成員函數的this指標也是常數型別。

當你在抽象基底類別的get_file_name()函數宣告後面加上const以後,這個函數內的this指標就從Image_file *const型別變成了const Image_file *const型,此時return file_name + std::string(".gif");裡的成員file_name是透過常數類型的this指標呼叫的。從而滿足了上述要求。

洪涛

const物件只能呼叫const成員函數

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板