Rebirth of C++ Cake Hands (under Classes and Objects)

Under classes and objects

  • foreword
  • 1. Initialization list
    • 1.1 Definition of initialization list
    • 1.2 The usefulness of the initialization list
    • 1.3explicit keyword
  • Two. Friends
    • 2.1 Definition of friend
    • 3.2 Friend functions
    • 3.3 Friend class
  • 3. static members
    • 3.1 Definition of static members
  • 4. Inner class
  • 5. Anonymous object
  • Summarize

Foreword

After learning the six default functions, we have already understood the knowledge of classes and objects, and we can handle 70 to 80% of the situation, but there are still some problems that we need to solve, and these problems we will be in Completely mastered in this article.

1. Initialization list

In the constructor function of the previous article, we said that the members of the class can be given default values when they are declared, and the setting of this default value involves the initialization list we learned today.

1.1 Definition of initialization list

After learning the constructor, we all know that to write a class, we must write its constructor, but we found some problems in our use:
If the member variable is to be initialized at the same time as the definition, for example: const and int & amp; of this type, and the member variable is of a class and this class does not have a default member function.

```cpp
class time
{<!-- -->
public:
Time(int hour, int minute, int second)
{<!-- -->
_hour = hour;
_minute = minute;
_second = second;
}
private:
int _hour;
int_minute;
int_second;
};
class A
{<!-- -->
public:
A(int year, int month, int day, int & p)
{<!-- -->
_year = year;
_month = month;
_day = day;
_x = 1;
_p = p;
_t;
}
private:
int_year;
int_month;
int_day;
//The definition needs to be initialized at the same time
const int _x;
int & _p;
// no default constructor
Time_t;
};
int main()
{<!-- -->
A a(2023, 8, 3);
return 0;
}

There will be problems with such code, and the appearance of the initialization list will solve this problem

Initialization list: Starts with a colon, followed by a comma-separated list of data members, each “member variable” followed by a comma strong>initial value or expression.

class time
{<!-- -->
public:
Time(int hour, int minute, int second)
{<!-- -->
_hour = hour;
_minute = minute;
_second = second;
}
private:
int _hour;
int_minute;
int_second;
};
class A
{<!-- -->
public:
A(int year, int month, int day, int & p)
:_x(1)//initialization list
,_p(p)
,_t(22,47,0)
{<!-- -->
_year = year;
_month = month;
_day = day;
}
void Print()
{<!-- -->
cout << _year << ' ' << _month << ' ' << _day << ' ' << _x << ' ' << _p << endl;
}
private:
int_year;
int_month;
int_day;
//The definition needs to be initialized at the same time
const int _x;
int & _p;
Time_t;
};
int main()
{<!-- -->
int p = 2;
A a(2023, 8, 3, p);
a.Print();
return 0;
}

Notice:

  1. Each member variable can only appear once in the initialization list (initialization can only be initialized once)
  2. The class contains the following members, which must be placed in the initializer list for initialization:
    reference member variable
    const member variable
    A custom type member (and the class has no default constructor)

1.2 The usefulness of the initialization list

In the constructor, we know that the constructor is the place where the member variables are initialized, but this concept needs to be a little more specific after we have learned the initialization list. The initialization function of the constructor is performed in the initialization list, and the function body is only carried out a specific assignment.

So why didn’t we get an error when we didn’t explicitly implement the initialization list when using the constructor before?
Because regardless of whether you use an initialization list or not, for a member variable of a custom type, it must be initialized with an initialization list first. The built-in type will be given a random value.

Here we can see that even though the three member variables of the built-in type are not explicitly implemented in the initialization list, they have been defined and then assigned in the function body.

class time
{<!-- -->
public:
Time(int hour = 1, int minute = 1, int second = 1)
{<!-- -->
_hour = hour;
_minute = minute;
_second = second;
}
private:
int _hour;
int_minute;
int_second;
};
class A
{<!-- -->
public:
A(int year, int month, int day, int & p)
:_x(1)
,_p(p)
//,_t(22,47,0)//Even if it is not written in the initialization list, it will be initialized with the initialization list
{<!-- -->
_year = year;
_month = month;
_day = day;
}
void Print()
{<!-- -->
cout << _year << ' ' << _month << ' ' << _day << ' ' << _x << ' ' << _p << endl;
}
private:
int_year;
int_month;
int_day;
//The definition needs to be initialized at the same time
const int _x;
int & _p;
Time_t;
};
int main()
{<!-- -->
int p = 2;
A a(2023, 8, 3, p);
a.Print();
return 0;
}

Notice:
The declaration order of member variables in the class is their initialization order in the initialization list, which has nothing to do with their order in the initialization list

1.3explicit keyword

We have learned about implicit type conversion in C language

int main()
{<!-- -->
int i = 1;
double b = 1.1;
i = b;//implicit type conversion
//That is, a temporary variable is created and assigned to b, and then this temporary variable is assigned to i.
int & amp; j = b;//Report an error, because the temporary variable is constant, which causes the enlargement of the authority.
return 0;
}

Well in C++ you also have implicit type conversions but the conditions are made more stringent.

Constructors can not only construct and initialize objects, but also have default values for a single parameter or no default value for the first parameter
The constructor also has the function of type conversion.

When explicit modifies the constructor, the role of single-argument constructor type conversion is prohibited

class A
{<!-- -->
public:
//Implicit type conversion of a single parameter
//explicit A(int a)
A(int a)
:_a(a)
{<!-- -->
cout << "A(int a)" << endl;
}
const void Print() const
{<!-- -->
cout << _a << endl;
}
private:
int _a;
};
class Date
{<!-- -->
public:
// Implicit type conversion of multiple parameters
//Note: Except for the first parameter, other parameters have default values
//explicit Date(int year, int month = 8, int day = 4)
Date(int year, int month = 8, int day = 4)
:_year(year)
,_month(month)
,_day(day)
{<!-- -->
cout << " Date(int year, int month = 8, int day = 4)" << endl;
}
const void Print()const//const objects cannot call non-const member functions
{<!-- -->
cout << _year << '/' << _month << '/' << _day << endl;
}
private:
int_year;
int_month;
int_day;
};
int main()
{<!-- -->
A a(1);//normal use constructor
A b = 2;//implicit type conversion
//The compiler constructs a temporary object of type A with 2 of type int
// Then use copy construction to generate b
//And under the optimization of the compiler, the construction plus copy construction is optimized into a construction
//
//
//A & amp; c = 2;//Compilation error, because the temporary object is constant, which involves the amplification of permissions
const A & amp; c = 3;//Adding const is the translation of permissions

Date d = 4;
const Date & d1 = 5;
//C++11
Date d2 = {<!-- --> 2023,8,4 };//Multi-parameter class, which also constitutes implicit type conversion
a.Print();
b. Print();
c.Print();
d.Print();
d1. Print();
d2. Print();

return 0;
}

![Insert picture description here](https://img-blog.csdnimg. cn/12fb20bf00b34a29b9f620e86ebd4a58.png

Two. Friends

In the middle part, we mentioned in operator overloading that when a function defined outside the class wants to access the private members of the class, it must either be overloaded as a member function or use a friend, so what exactly is a friend?

2.1 Definition of friend

Friends provide a way to break out of encapsulation, and sometimes convenience. But friends will increase coupling and destroy encapsulation, so
Youyuan should not be used more.

Friends are divided into: friend function and friend class

3.2 Friend function

In the use of classes, we often need to print out the member variables of the class, but we always need to call this member function, so we can use the knowledge of operator overloading to extract the stream << to reload.

class A
{<!-- -->
public:
A(int year, int month, int day, int & p)
:_year(year)
,_month(month)
,_day(day)
{<!-- -->
}
void Print()
{<!-- -->
cout << _year << '/' << _month << '/' << _day << endl;
}
//If it is defined in the class, because the this pointer preempts the position of the first parameter
ostream & amp; operator<< (ostream & amp; out)
{<!-- -->
out << _year << '/' << _month << '/' << _day << endl;
return out;
}
private:
int_year;
int_month;
int_day;
\t
};
//ostream & amp; operator<< (ostream & amp; out, A & amp; a)
//{<!-- -->
// out << a._year << '/' << a._month << '/' << a._day << endl;
// return out;
//}
// Outside the class we cannot access the private members of the class
int main()
{<!-- -->
int p = 2;
A a(2023, 8, 3, p);
a.Print();
a << cout;
//Whether it is from the value of the code or the habits we use, it is very bad
return 0;
}

Friend functions can directly access a private member of a class, which is a ordinary class defined outside function, which does not belong to any class, but needs to be in the
The internal declaration of the class needs to add the friend keyword when declaring.

class A
{<!-- -->
friend ostream & amp; operator<< (ostream & amp; out, A & amp; a);//friend statement
public:
A(int year, int month, int day, int & p)
:_year(year)
,_month(month)
,_day(day)
{<!-- -->}
void Print()
{<!-- -->
cout << _year << '/' << _month << '/' << _day << '/' << endl;
}
private:
int_year;
int_month;
int_day;
\t
};
ostream & amp; operator<< (ostream & amp; out, A & amp; a)//friend function of class A
{<!-- -->
out << a._year << '/' << a._month << '/' << a._day << endl;
return out;
}
int main()
{<!-- -->
int p = 2;
A a(2023, 8, 3, p);
//a << cout;
cout << a;
return 0;
}

Notice:

  1. A friend function can access private and protected members of a class, but is not a member function of the class.
  2. Friend functions cannot be modified with const.
  3. Friend functions can be declared anywhere in a class definition, not restricted by class access qualifiers.
  4. A function can be a friend function of multiple classes.
  5. The principle of calling a friend function is the same as that of a normal function.

3.3 Friend class

Not only can a function be declared as a friend relationship, but also an entire class can be declared as a friend relationship

class time
{<!-- -->
friend class Date;//declare that the Date class is a friend of Time, and the Date class can access the private members of Time
//The Time class cannot access the private members of the Date class
public:
Time(int hour = 1, int minute = 1, int second = 1)
:_hour(hour)
,_minute(minute)
,_second(second)
{<!-- -->}
private:
int _hour;
int_minute;
int_second;
};
class Date
{<!-- -->
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
,_t(23,39,0)
{<!-- -->}
void Print()
{<!-- -->
cout << _t._hour << ':' << _t._minute << ':' << _t._second << endl;
cout << _year << '/' << _month << '/' << _day << endl;
}
private:
int_year;
int_month;
int_day;
Time_t;
};
int main()
{<!-- -->
Date d(2023, 8, 3);
d.Print();
return 0;
}

Notice:

  1. All member functions of a friend class can be friend functions of another class, and can access non-public members of another class.
  2. The friendship relationship is one-way and not exchangeable.
  3. The friendship relationship cannot be transmitted. If C is a friend of B and B is a friend of A, it cannot be explained that C is a friend of A.
  4. The friendship relationship cannot be inherited, and I will give you a detailed introduction in the inheritance position.

three.static members

In class learning, the member variables and functions we define have different values in each object, and they all exist in the stack frame of their respective objects. But what if we need a member variable or function that belongs to all classes instead of a member variable or function of a certain class? This requires us to define static member variables or functions

3.1 Definition of static members

A class member declared as static is called a static member of a class, and a member variable modified with static is called a static member variable ; with
A member function modified by static is called a static member function. Static member variables must be initialized outside the class.

When we need to implement a class, calculate how many class objects are created and how many class objects are being used in the program

//1. Normal use
// how many classes are created
int n = 0;
// how many classes are being used
int m = 0;
class A
{<!-- -->
public:
A()
{<!-- -->
n + + ;
m++;
}
A (A & a)
{<!-- -->
n + + ;
m++;
}
~A()
{<!-- -->
m--;
}
};
int main()
{<!-- -->
A a;
A a1;
cout << n << ' ' << m << endl;
A();//Anonymous object
cout << n << ' ' << m << endl;
return 0;
}
//The disadvantages are obvious, C++ pays attention to encapsulation but the values of n and m can be modified at will
//But if it is defined as a member variable, it cannot be accessed outside the class and the n and m values of each object are different


//2. Static member method
class A
{<!-- -->
public:
A()
{<!-- -->
n + + ;
m++;
}
A (A & a)
{<!-- -->
n + + ;
m++;
}
~A()
{<!-- -->
m--;
}
// static member function
static void Print()
{<!-- -->
cout << n << ' ' << m << endl;
}
private:
// static member declaration
static int n;
static int m;
};

// Static member definition initialization
//must be outside the class
int A::n = 0;
int A::m = 0;

int main()
{<!-- -->
A a;
A a1;
A* n = nullptr;
A();

//Static member variables are private and cannot be accessed outside the class
/*cout << n << ' ' << m << endl;*/

//If the static member variable is public, the following four ways can break through the class domain to access
/*a.n;
a1.n;
n->n;
A().n;*/

//If defined as a member variable, each object needs to be called, which reduces the value and readability of the code
/*a.Print();
a1. Print();
n->Print();
A().Print();*/
\t
A::Print();
return 0;
}

Notice:

  1. Static members are shared by all class objects, do not belong to a specific object, and are stored in the static area.
  2. Static member variables must be defined outside the class, do not add the static keyword when defining, and only declare in the class.
  3. Class static members can be accessed with class name::static member or object.static member.
  4. Static member functions do not have a hidden this pointer and cannot access any non-static members.
  5. Static members are also members of a class, subject to public, protected, private access qualifiers.

Four. Internal classes

Concept: If a class is defined inside another class, the inner class is called an inner class. The inner class is an independent class, it does not belong to the outer class, let alone access the members of the inner class through the object of the outer class. Outer classes do not have any privileged access to inner classes.

Note: The inner class is the friend class of the outer class, see the definition of the friend class, the inner class can be accessed through the object parameter of the outer class
Ask all members in the outer class. But the outer class is not a friend of the inner class.

class Date
{<!-- -->
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
, _day(day)
{<!-- -->}
void Print()
{<!-- -->
cout << _year << '/' << _month << '/' << _day << endl;
}
//Date class is born as a friend of Time class
class time
{<!-- -->
public:
Time(int hour = 1, int minute = 1, int second = 1)
:_hour(hour)
, _minute(minute)
, _second(second)
{<!-- -->}
void Print(const Date & d)
{<!-- -->
cout << _hour << ':' << _minute << ':' << _second << endl;
cout << d._year << '/' << d._month << '/' << d._day << endl;
}
private:
int _hour;
int_minute;
int_second;
};
private:
int_year;
int_month;
int_day;
};
int main()
{<!-- -->
Date d(2023, 8, 3);
Date::Time t(23, 49, 1);
t.Print(d);
return 0;
}

characteristic:

  1. The inner class can be defined in the public, protected, and private of the outer class.
  2. Note that the inner class can directly access the static members in the outer class without the object/class name of the outer class.
  3. sizeof(outer class) = outer class, has nothing to do with inner class.

5. Anonymous object

When we use classes, we find that sometimes we don’t need to define a class specifically, because we only need a certain function in the class. At this time, it is time for our anonymous object to play.

class A
{<!-- -->
public:
A(int a = 1)
:_a(a)
{<!-- -->
cout << "A(int a)" << endl;
}
~A()
{<!-- -->
cout << "~A()" << endl;
}
int Add(int b ,int c)
{<!-- -->
return b + c;
}
private:
int _a;
};
int main()
{<!-- -->
// famous object
A a1;
// anonymous object
A();
//We use the Add function normally
A a;
cout << a.Add(2, 3) << endl;
//Use an anonymous object to use the Add function
cout << A(). Add(2, 3) << endl;
return 0;
}

characteristic:

  1. Anonymous objects do not need to be named
  2. The life cycle of an anonymous object has only one line, and the next line will call the destructor

Summary

This is the end of the study of classes and objects. Classes and objects involve a lot. In the first part, we learned about the definition of classes, access qualifiers, etc. In the second part, we learned the use of six default functions, and in the second part Here we learned about initialization lists, friends, static members, etc. This knowledge is cumbersome and complicated and requires us to brush it twice or even three times, and everyone needs to get started to use it to understand it more deeply. Goodbye is not farewell. In the next article, I will introduce you to the knowledge about memory and templates in C ++. Look forward to it!