There are almost no restrictions on the scope of use of const
and volatile
const
or volatile
can appear after the parameters of the instance member function, both of which are used to modify the object pointed to by the implicit parameter this of the function.
const
appears after the parameter list of the instance function object, indicating that the object pointed to by this
is a read-only object that cannot be modified.
However, you can modify the non-read-only static data members of the object pointed to by this.
const
, volatile
, const volatile
appears after the instance function member parameter list, if these instance function objects have implicit parameters this
is different, it can be regarded as an overloaded function.
When calling an instance function member, the compiler will match the type of the actual parameter with the type of this
, thereby calling the most appropriate instance function member.
Ordinary variables or objects that can be read/written should call instance function members without const
or volatile
after the parameter list.
const
objects should call instance function members with const
after the parameter list.
volatile
objects should call instance member functions with volatile
after the parameter list
Note that if there is no corresponding instance function member when calling, an error will be reported.
Let’s take a look at an example. This example all calls the corresponding function in a matching manner.
#include<iostream> using namespace std; class A {<!-- --> int a; const int b; public: int f() {<!-- --> cout << "f() " << endl; a + + ; //b + + ; cannot be modified return a; } int f()volatile {<!-- --> cout << "volatile f()" << endl; a + + ; // You can modify the instance member data member of this class volatile int a //b + + ; return a; } int f() const volatile {<!-- --> cout << "f() const volatile " << endl; // a + + ; is also wrong return a; } int f()const {<!-- --> cout << "f() const " << endl; // a + + ; is also wrong return a; } A(int x) :b(x) {<!-- --> a = x; } }; A w(3); // This is a writable object const A x(6); // This is a readable object volatile A y(6); // Define volatile objects const volatile A z(8); // Define a readable volatile object int main() {<!-- --> w.f(); x.f(); y.f(); z.f(); }
The final result is as follows:
Let’s analyze the four function members f() above. These four function members are overloaded functions. Their display parameter list does not define any formal parameters, but the type of the implicit formal parameter this
Different, this
is used to point to the object of the current function.
Let’s think about it in depth. If there is no perfect match, will the compiler fall back to calling the second matching function?
Look at the code below. I commented both fun() const and fun() volatile to see how the situation changes.
#include<iostream> using namespace std; class A {<!-- --> int a; const int b; public: int f() {<!-- --> cout << "f() " << endl; a + + ; //b + + ; cannot be modified return a; } //int f()volatile {<!-- --> // cout << "volatile f()" << endl; // a + + ; // You can modify the instance member data member of this class volatile int a // //b + + ; // return a; //} int f() const volatile {<!-- --> cout << "f() const volatile " << endl; // a + + ; is also wrong return a; } //int f()const {<!-- --> // cout << "f() const " << endl; // // a + + ; is also wrong // return a; //} A(int x) :b(x) {<!-- --> a = x; } }; A w(3); // This is a writable object const A x(6); // This is a readable object volatile A y(6); // Define volatile objects const volatile A z(8); // Define a readable volatile object int main() {<!-- --> w.f(); x.f(); y.f(); z.f(); }
The running results are as follows
We can see that const A x(6)
and volatile A y(6)
both called f( because they could not find the most suitable matching function. ) const volatile
Let’s look at another code and comment out only the f() const volatile function to see how
#include<iostream> using namespace std; class A {<!-- --> int a; const int b; public: int f() {<!-- --> cout << "f() " << endl; a + + ; //b + + ; cannot be modified return a; } int f()volatile {<!-- --> cout << "volatile f()" << endl; a + + ; // You can modify the instance member data member of this class volatile int a //b + + ; return a; } //int f() const volatile {<!-- --> // cout << "f() const volatile " << endl; // // a + + ; is also wrong // return a; //} int f()const {<!-- --> cout << "f() const " << endl; // a + + ; is also wrong return a; } A(int x) :b(x) {<!-- --> a = x; } }; A w(3); // This is a writable object const A x(6); // This is a readable object volatile A y(6); // Define volatile objects const volatile A z(8); // Define a readable volatile object int main() {<!-- --> w.f(); x.f(); y.f(); z.f(); }
Discover
Reason for error
We will call f() const annotation on the basis of just now
#include<iostream> using namespace std; class A {<!-- --> int a; const int b; public: int f() {<!-- --> cout << "f() " << endl; a + + ; //b + + ; cannot be modified return a; } int f()volatile {<!-- --> cout << "volatile f()" << endl; a + + ; // You can modify the instance member data member of this class volatile int a //b + + ; return a; } //int f() const volatile {<!-- --> // cout << "f() const volatile " << endl; // // a + + ; is also wrong // return a; //} //int f()const {<!-- --> // cout << "f() const " << endl; // // a + + ; is also wrong // return a; //} A(int x) :b(x) {<!-- --> a = x; } }; A w(3); // This is a writable object const A x(6); // This is a readable object volatile A y(6); // Define volatile objects const volatile A z(8); // Define a readable volatile object int main() {<!-- --> w.f(); x.f(); y.f(); z.f(); }
Let’s see how to report an error
Let’s do a final experiment and just comment out the f() function to see what happens.
#include<iostream> using namespace std; class A {<!-- --> int a; const int b; public: //int f() {<!-- --> // cout << "f() " << endl; // a + + ; // //b + + ; cannot be modified // return a; //} int f()volatile {<!-- --> cout << "volatile f()" << endl; a + + ; // You can modify the instance member data member of this class volatile int a //b + + ; return a; } int f() const volatile {<!-- --> cout << "f() const volatile " << endl; // a + + ; is also wrong return a; } int f()const {<!-- --> cout << "f() const " << endl; // a + + ; is also wrong return a; } A(int x) :b(x) {<!-- --> a = x; } }; A w(3); // This is a writable object const A x(6); // This is a readable object volatile A y(6); // Define volatile objects const volatile A z(8); // Define a readable volatile object int main() {<!-- --> w.f(); x.f(); y.f(); z.f(); }
The following error was found:
To sum up, the overall priority is as follows:
Nothing
> const
and volatile
> const volatile
Let me explain, if an object does not contain const
and volatile
, then it will be called first if it does not contain const
and volatile
> function, if not, call one of f() const
or f() volatile
. If both exist, the compiler does not know which one to call. , an error will be reported. If neither f() const
nor f() volatile
exists, then f() const volatile
will be called.
The same is true if the object is of type const
. First look for f() const
, and then call f() const volatile
if it cannot be found.
And add a small point, const
and volatile
cannot appear after the parameter list of the constructor or destructor, because when constructing or destructing an instance object, the object must It can be modified and must be in a stable state (volatile means it is a volatile object)