编程菜鸟,在学习c++多态性的过程中,写了这样的测试代码,这里会有类型限定符不兼容。
当我在抽象基类的函数声明后添加上const后,就不会出现类型不兼容,这是为什么?
PHP中文网2017-04-17 13:22:14
const限定的變數以及其引用只能呼叫const限定的成員函數
const限定代表變數的值不會改變,而要想不改變變數的值則只能呼叫const修飾的成員函數
高洛峰2017-04-17 13:22:14
你的問題其實與多態無關,要解答你這個問題需要兩個方面的知識點。
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
到底是函數的參數還是物件的成員。
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
指標呼叫的。從而滿足了上述要求。