Const-qualified variables and their references can only call const-qualified member functions Const-qualified means that the value of the variable will not change. If you want to not change the value of the variable, you can only call const-modified member functions
Your question actually has nothing to do with polymorphism. To answer your question, two aspects of knowledge are needed.
1. Member function’s this pointer
First of all, to access the members of the class within the member function of the class, you need to access it through the this pointer (it can be omitted if the name does not conflict). When calling a member function through an object, the object itself will be passed through the this pointer Passed to member function. For example:
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
}
Why can I access the member a.get() of object a in the x function? Just through this this pointer. When calling a through a.get(), the compiler will assign the address of object a to the this pointer, where the type of the this pointer is A *const. Within the get() function, the statement return x; is actually equivalent to return this->x;, so we can access the member a.get() of the object a through x.
Similarly, why can a.set(10); assign the value of member a of object x to 10? Also through the this pointer. x = xx; is equivalent to this->x = xx;.
In the above two cases, since there is no ambiguity in the parsing of x, the this pointer can be omitted. However, what if I want to use the same variable name as the member set in the parameters of the member function x? Still distinguished by the this pointer. We can modify the definition of member function set as follows:
A::void set(int x) { this->x = x; }
The this pointer here cannot be omitted, otherwise, there will be ambiguity when written as x = x;, and the compiler cannot resolve whether x is a parameter of a function or a member of an object.
2. constMember functions
Consider a situation. In the previous example, our object a is a non-constant object. What if we want to use class A to declare a constant object? For example
int main() {
const int ci = 10;
int i = ci;
const A ca(5); // ca.x = 5
int j = ca.get(); // 编译错误
}
For built-in types, you can directly define a constant ci and use its value. For our own defined class A, we can also use the same method to define constants ca and obtain the value of member ca.get() of object a through x.
However, when using member functions to obtain the value of its data member x, we actually still access the member this through the x pointer. The problem is that at this time, the this pointer is not const A *const type, but A *const type. We know that the content of a constant cannot be accessed through a non-const pointer, that is,
const int ci = 5;
int *p = &ci; // 错误
const int *cp = &ci; // 正确
So how to access member this through x pointer? We need to find a way to make the this pointer into a const A *const type. The way is to add the const keyword at the end of the class member function declaration, which means that the member function is
const member function, and the this pointer within the function is a constant type. For example, we can overload the get() method:
int A::get() const { return x; }
At this time,
int j = ca.get(); // j = 5
It will run normally.
Application
Specific to your question,
When I add const after the function declaration of the abstract base class, there will be no type incompatibility. Why is this?
In the store_file() function, its parameter img_file is a constant reference type. If you want to call a member function through a constant object, you need the this pointer of the member function of this object to also be a constant type.
When you add get_file_name() after the const function declaration of the abstract base class, the this pointer in this function changes from the Image_file *const type to the const Image_file *const type. At this time, return file_name + std::string(".gif"); The member file_name in is called through the this pointer of constant type. Thus the above requirements are met.
Const-qualified variables and their references can only call const-qualified member functions
Const-qualified means that the value of the variable will not change. If you want to not change the value of the variable, you can only call const-modified member functions
Your question actually has nothing to do with polymorphism. To answer your question, two aspects of knowledge are needed.
1. Member function’s
this
pointerFirst of all, to access the members of the class within the member function of the class, you need to access it through the
this
pointer (it can be omitted if the name does not conflict). When calling a member function through an object, the object itself will be passed through thethis
pointer Passed to member function. For example:Why can I access the member
a.get()
of objecta
in thex
function? Just through thisthis
pointer. When callinga
througha.get()
, the compiler will assign the address of objecta
to thethis
pointer, where the type of thethis
pointer isA *const
. Within theget()
function, the statementreturn x;
is actually equivalent toreturn this->x;
, so we can access the membera.get()
of the objecta
throughx
.Similarly, why can
a.set(10);
assign the value of membera
of objectx
to 10? Also through thethis
pointer.x = xx;
is equivalent tothis->x = xx;
.In the above two cases, since there is no ambiguity in the parsing of
x
, thethis
pointer can be omitted. However, what if I want to use the same variable name as the memberset
in the parameters of the member functionx
? Still distinguished by thethis
pointer. We can modify the definition of member functionset
as follows:The
this
pointer here cannot be omitted, otherwise, there will be ambiguity when written asx = x;
, and the compiler cannot resolve whetherx
is a parameter of a function or a member of an object.2.
const
Member functionsConsider a situation. In the previous example, our object
a
is a non-constant object. What if we want to use classA
to declare a constant object? For exampleFor built-in types, you can directly define a constant
ci
and use its value. For our own defined classA
, we can also use the same method to define constantsca
and obtain the value of memberca.get()
of objecta
throughx
.However, when using member functions to obtain the value of its data member
x
, we actually still access the memberthis
through thex
pointer. The problem is that at this time, thethis
pointer is notconst A *const
type, butA *const
type. We know that the content of a constant cannot be accessed through a non-const pointer, that is,So how to access member
this
throughx
pointer? We need to find a way to make thethis
pointer into aconst A *const
type. The way is to add theconst
keyword at the end of the class member function declaration, which means that the member function isconst
member function, and thethis
pointer within the function is a constant type. For example, we can overload theget()
method:At this time,
It will run normally.
Application
Specific to your question,
In the
store_file()
function, its parameterimg_file
is a constant reference type. If you want to call a member function through a constant object, you need thethis
pointer of the member function of this object to also be a constant type.When you add
get_file_name()
after theconst
function declaration of the abstract base class, thethis
pointer in this function changes from theImage_file *const
type to theconst Image_file *const
type. At this time,return file_name + std::string(".gif");
The memberfile_name
in is called through thethis
pointer of constant type. Thus the above requirements are met.