c++ constant details

  • 2020-05-24 05:52:03
  • OfStack

concept

Constants hold fixed and immutable values. Once the initial value is determined, it cannot be changed elsewhere in the program, so the const object must be initialized. The constant 1 is usually decorated with the const keyword.

const objects can be roughly divided into three categories:

1. const int a

const int a =10;
int const b =10;

The two formats are identical. That is to say, neither const nor int affects the semantics. With that in mind, let's look at these two guys: const int * pi and int const * pi. Do they have different semantics?

Just remember that 1 point, int and const, which is put before and which is put after, are the same, just like const int n; With int const n; 1 sample. In other words, they're the same.

2. const int * p

As mentioned above, const int * p is exactly the same as int const * p.

Let's see what they mean by the following examples.


int a =30; 
int b =40; 
const int * p=&a; 
p=&b;   // Notice here, p You can reassign at any time 1 Three new memory addresses  
b=80;   // Think about it: it works here *pi=80; Instead? Of course not  
printf(  " %d " , *p ) ;  // The output is 80 

Semantic analysis:

The value of p can be modified. That is, it can be redirected to another address, but the value of b cannot be modified by *p.

First, const modifies the entire *p (note *p, not p). So *p (the object to which p points) is a constant and cannot be assigned (although b, which p refers to, is a variable, not a constant).
Second, p is not modified with const, so p is a pointer variable that can be assigned to repoint to another memory address.

You may be wondering: how do you modify pi with const? In fact, if you notice the location of const in int * const pi, you get the idea. Remember, look at the semantics in terms of format. Let's look at the definition below.

3. int* const p

Here, const modifies p, instead of *p above. We will analyze it according to the following example:


int a=30; 
int b=40; 
int * const p=&a; 
//p=&b;   
 Notice here, p You can't do this anymore, you can't point to anything else 1 Three new addresses.  
b=80;   
// Here can use *p=80; Instead? Yes, you can go through here *p Modify the a The value of the.  
// Please move yourself with the front 1 Let me give you an example.  
printf(  " %d " , *p ) ;  // The output is 80 

*p=100;

printf(  " %d " , a ) ;  // The output is 100

Semantic analysis:

The p value cannot be re-assigned and modified. It can only always point to the memory address at the time of initialization. And you can modify the value of a by *p. Compare 1 with the previous example! Look at the following two analyses

1). p is just a pointer constant because of the const modifier: that is, the p value is unmodifiable (that is, p cannot point back to the b variable).

2). There is no modification of const in front of the whole *p. In other words, *p is a variable rather than a constant, so we can modify the value of a by *p.

In a sentence, this time p is a pointer constant to data of type int.
Two final sentences:
1). If the modification of const is before *p, what cannot be changed is *p instead of p
2). If const is directly written before p, p cannot be changed.

4. Add three situations.

Here, I add the following three cases. In fact, as long as the above semantics are clear, the three cases have been included. But as three concrete forms, I'll just mention one!

Case 1: the int * pi pointer points to the const int n constant


const int n1=40; 
int *pi; 
pi=&n1;// Is that ok? No, VC The following is a compilation error. const int  The type of n1 The address is not assigned to the point int A pointer to a type address pi . Otherwise, pi Is it possible to modify n1 Is it worth it?   
pi=(int* ) &n1;  // Is that ok? Casts can be C Supported.  VC The following compilation passed, but still failed *pi=80 To modify the n1 The value of the. Go for it! Let's see how that works. 

Case 2: const int * pi pointer points to const int n1


const int n1=40; 
const int * pi; 
pi=&n1;// The two types are the same and can be assigned like this. n1 The value of either through pi or n1 It can't be changed. 

Case 3: pointer declared with const int * const pi


int n; 
const int * const pi=&n; 
// Can you imagine pi Can anything be done? pi You can't change the value, you can't pass it pi Modify the n The value of the. Because no matter  
//*pi or pi Are all const . 

5. Constant references


int a = 10;
int& p1 = a;// correct 
int& p2 = 2;// Error, need to reference lvalue 
const int& p3 = a;// correct 
const int& p4 = 4;// correct 

Two things are worth noting about reference initialization:

(1) when the initialization value is 1 lvalue (address can be obtained), there is no problem. Constant or extraordinary references can be used, such as p1 and p3.
(2) when the initialization value is not one lvalue, it can only be used for one const T & (constant reference) assignment. Such as p2, p3. And this assignment has a process:

First, the value is implicitly converted to type T, then the result of the conversion is stored in a temporary object, which is then used to initialize the reference variable.

If you are referring to a constant, the compiler first creates a temporary variable and then places the value of that constant in the temporary variable. A reference to a constant can be initialized with any other reference. But you can't change it.

6. Constant function, constant reference parameter, constant reference return value

Example 1: bool verifyObjectCorrectness(const myObj & obj); //const reference parameter
Example 2: void Add(const int & arg) const; //const function
Example 3: IStack const & GetStack() const { return _stack; } //return const reference

6.1 constant functions
1. A function is declared a constant by adding the keyword const to it
2. In C++, it only makes sense to declare member functions as constants. A constant member function with an const suffix is also known as an inspector (inspector), no
An extraordinary member function with an const suffix is called a mutant (mutator)
3. const related errors are always found at compile time
[abstract]If the function not declared const, in can not be a const object, and the compiler will
give an error message. A const function can be applied to a non-const object
5. In C++, all methods of an object receive an implied this pointer to the object itself; The constant method gets an implied pointer to the constant this
void func_name const ();
This means that the function func_name() does not change *this. You understand this when you think of the this pointer as an invisible parameter to the function func_name()
void func_name(T *this) (no const)
void func_name(const T *this) (const)
6. Constant functions can be called by any object, while non-constant functions can only be called by non-constant objects, and cannot be called by non-constant objects, such as:


class Fred {
 public:
  void inspect() const;  // This member promises NOT to change *this
  void mutate();     // This member function might change *this
 };
 
 void userCode(Fred& changeable, const Fred& unchangeable)
 {
  changeable.inspect();  // OK: doesn't change a changeable object
  changeable.mutate();  // OK: changes a changeable object
 
  unchangeable.inspect(); // OK: doesn't change an unchangeable object
  unchangeable.mutate(); // ERROR: attempt to change unchangeable object
 }

7. Allow constant and nonconstant functions of the same name in a class, and the compiler selects the appropriate function based on the object on which the function is called
When the nonconstant object calls the function, the nonconstant function is called first;
When a constant object calls this function, only a constant function can be called.
If there is only a constant function in a class and no non-constant function with the same name, both the non-constant and the constant objects can call the constant function. Such as:


#include <iostream>
using namespace std;
 
struct A
{
  void f() const { cout<<"const function f is called"<<endl; }
  void f() { cout<<"non-const function f is called"<<endl; }
  void g() { cout<<"non-const function g is called"<<endl; }
};
 
void main()
{
  A a;
  const A& ref_a = a;
  a.f(); //calls void f() And the output: non-const function f is called<br>  ref_a.f();//calls void f () const,  Output: const function f is called

 a.g(); //ok, normal call <br>  ref_a.g(); //error, const object can not call non-const function 
}

8. The const keyword cannot be used in constructors and destructors. Because the purpose of the constructor is to initialize the field value, it must change the object, as does the destructor

6.2 constant references parameters

In this example, an object of type myObj, obj, is passed in by reference to the function verifyObjectCorrectness. To be safe, the const keyword is used to ensure that the function verifyObjectCorrectness does not change the state of the object referenced by the object obj. In addition, by declaring parameter constants, users of functions can ensure that their objects are not changed and do not have to worry about side effects when calling functions. The following code attempts to modify the parameter declared as a constant reference so that it does not compile!


#include <iostream>
using namespace std;
 
class Test
{
public:
  void f(const int& arg);
private:
  int value;
};
  
void Test::f(const int& arg) {
  arg=10; // Try to modify arg This line will cause a compiler error  //error C2166: l-value specifies const object
  cout<<"arg="<<arg<<endl;
  value=20;
} 
 
void main()
{
 int i=7;
 Test test;
 test.f(i);
 cout<<"i="<<i<<endl;
}

6.3 constant references return values

If you want to return a member of an this object by reference from a constant method (function), you should use a constant reference to return it, const X &
That is, if what you want to return by reference is logically part 1 of the this object (regardless of whether it is physically embedded in the this object), then constant methods need to return by constant reference or by value, not by nonconstant reference


class Person {
public:
  const string& name_good() const; // Right: the caller can't change the name
  string& name_evil() const;    // Wrong: the caller can change the name
  .
};
 
void myCode(const Person& p) // You're promising not to change the Person object
{
  p.name_evil() = "Igor"; // but you changed it anyway!!
}


Related articles: