[C + + from 0 to 1] Part 5: classes and objects

Posted by NewBob on Mon, 31 Jan 2022 18:11:52 +0100

1, On constructor

1.1 constructor body assignment

When creating an object, the compiler calls the constructor to give each member variable in the object an appropriate initial value

class Date
{
public:
Date(int year, int month, int day)
{
    _year = year;
    _month = month;
    _day = day;
}
private:
    int _year;
    int _month;
    int _day;
};

Although there is an initial value in the object after the above constructor call, it cannot be called initialization of class object members. The statements in the constructor body can only be called initial value, not initialization. Because initialization can only be initialized once, and the constructor body can be assigned multiple times.

1.2 initialization list

Initialization list: start with a colon, followed by a comma separated list of data members. Each "member variable" is followed by an initial value or expression in parentheses

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};

be careful

  1. Each member variable can only appear once in the initialization list (initialization can only be initialized once)
  2. Class contains the following members, which must be placed in the initialization list for initialization:
    const member variable
#include <iostream>
using namespace std;

class Date
{
public:

	Date(int year = 1, int month = 1, int day = 1)
	{
	    _N = 10;
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;

	const int _N;//Constants must be initialized at definition time
};

int main()
{
	return 0;
}


At this point, you need to initialize the list: (where the member variable is defined)

It is also possible to define the initialization list in this way, but the above definition is more recommended.

Reference member variable

Custom type member (this class has no default constructor)

3. Try to use the initialization list for initialization, because no matter whether you use the initialization list or not, for custom type member variables, you must use the initialization list first.
4. The declaration order of member variables in the class is the initialization order in the initialization list, which is independent of the order in the initialization list
Look at the following code:

#include <iostream>
using namespace std;

class A
{
public:
	A(int a)
		:_a1(a)
		, _a2(_a1)
	{}

	void Print()
	{
		cout << _a1 << " " << _a2 << endl;
	}

private:
	int _a2;
	int _a1;
};

int main() 
{
	A aa(1);
	aa.Print();
	return 0;
}
//A. Output 1 1 B, program crash C compilation does not pass D, output 1 random value


Suggestion: for a class, try to keep the order of declaration consistent with the order of initialization list.

1.3 explicit keyword

Constructors can not only construct and initialize objects, but also have the function of type conversion for constructors with single parameters


Modifying the constructor with explicit will prohibit the implicit conversion of single parameter constructor

2, static member

2.1 concept

Class members declared as static are called static members of the class, and member variables modified with static are called static member variables; The member function modified with static is called static member function. Static member variables must be initialized outside the class

Interview question: how many class objects are created in the program when implementing a class

#include <iostream>
using namespace std;

class A
{
public:
	A(int a = 1)//Constructor
		:_a(a)
	{
		++_sCount;
	}

	A(const A& aa)//copy constructor 
		:_a(aa._a)
	{
		++_sCount;
	}

	static int GetCount()//Static member function, without this pointer, can only access static member variables and member functions
	{
		return _sCount;
	}

private:
	int _a;
	static int _sCount;//Static variables belong to the whole class, all objects, and the life cycle is in the whole running period
};

int A::_sCount = 0;//Definition initialization (special example)

int main()
{
	A a1;
	A a2(1);
	//Both methods can be output
	cout << a2.GetCount() << endl;
	cout << A::GetCount() << endl;
	return 0;
}

2.2 characteristics

  1. Static members are shared by all class objects and do not belong to a specific instance
  2. Static member variables must be defined outside the class without adding the static keyword
  3. Class static members are available class names: static members or objects Static members to access
  4. Static member functions have no hidden this pointer and cannot access any non static members
  5. Like ordinary members of a class, static members also have three access levels: public, protected and private, and can also have return values.

[question]
Can static member functions call non static member functions? may not
Can a non static member function call a static member function of a class? sure

3, A new method of member initialization in C++11

C++11 supports initialization and assignment of non static member variables during declaration, but it should be noted that this is not initialization, but the default value of declared member variables.

4, Friends

Friends are divided into: friend function and friend class
Friends provide a way to break through encapsulation, sometimes providing convenience. However, friends will increase the degree of coupling and destroy the package, so friends should not be used more.

4.1 friend function


d1 prints the date by calling the PrintDate function.

So we need to overload <.

#include <iostream>
using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void PrintDate() const  // const Date& this
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	ostream& operator<<(ostream& out);//Overloaded into a member function, it is awkward to call it

private:
	int _year;
	int _month;
	int _day;
};

ostream& Date::operator<<(ostream& out)
{
	cout << _year << "-" << _month << "-" << _day << endl;
	return out;
}

int main()
{
	Date d1;
	//d1.PrintDate();
	//cout << d1 << endl;// Call no
	d1 << cout << endl;
	return 0;
}


Question:
Now we try to overload operator < <, and then find that we can't overload operator < < into member function * *. Because the output stream object of cout and the implied this pointer are seizing the position of the first parameter * *. The this pointer defaults to the first parameter, which is the left operand. However, in actual use, cout needs to be the first formal parameter object before it can be used normally. So we need to overload operator < < into a global function. But in this case, there will be no way to access members outside the class, so friends are needed to solve it.

#include <iostream>
using namespace std;

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);//friend function

public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void PrintDate() const  // const Date& this
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& out, const Date& d)
{
	cout << d._year << "-" << d._month << "-" << d._day << endl;
	return out;
}


Similarly, input is the same:

#include <iostream>
using namespace std;

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);//Declare as friend function
	friend istream& operator>>(istream& in, Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void PrintDate() const  // const Date& this
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "-" << d._month << "-" << d._day << endl;
	return out;
}

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

A friend function can directly access the private members of a class. It is an ordinary function defined outside the class and does not belong to any class, but needs to be declared inside the class. When declaring, you need to add the friend keyword
explain:

  • Friend functions can access private and protected members of a class, but not member functions of a class
  • Friend functions cannot be modified with const
  • Friend functions can be declared anywhere in the class definition and are not limited by the class access qualifier
  • A function can be a friend function of multiple classes
  • The calling principle of friend function is the same as that of ordinary function

4.2 friend category

All member functions of a friend class can be friend functions of another class and can access non-public members of another class.

#include <iostream>
using namespace std;

class Date; // forward declaration 
class Time
{
	friend class Date; // If you declare that the date class is a friend class of the Time class, you can directly access the private member variables in the Time class in the date class
public:
	Time(int hour = 0, int minute = 0, int second = 0)
		: _hour(hour)
		, _minute(minute)
		, _second(second)
	{}

private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	void SetTimeOfDate(int hour, int minute, int second)
	{
		// Direct access to private member variables of time class
		_t._hour = hour;
		_t._minute = minute;
		_t._second = second;
	}

private:
	int _year;
	int _month;
	int _day;
	Time _t;
};

  • Friend relationship is unidirectional and not exchangeable.
  • Friend relationship cannot be passed
    If B is A friend of A and C is A friend of B, the friend of A at C cannot be explained.

5, Inner class

5.1 concept and characteristics

Concept: if a class is defined inside another class, this inner class is called an inner class. Note that the internal class is an independent class at this time. It does not belong to the external class, and the internal class cannot be called through the object of the external class. External classes do not have any superior access rights to internal classes.

Note: the inner class is the friend class of the outer class. Note the definition of the friend class. The inner class can access all members of the outer class through the object parameters of the outer class. But the outer class is not a friend of the inner class.

characteristic:

  1. Internal classes can be defined in public, protected and private of external classes.
  2. Note that the internal class can directly access the static and enumeration members in the external class without the object / class name of the external class.
  3. Sizeof (external class) = external class, which has nothing to do with internal class.

6, Understand encapsulation again

C + + is an object-oriented program. Object-oriented has three characteristics: encapsulation, inheritance and polymorphism.

Through classes, C + + combines the attributes and behaviors of an object to make it more in line with people's cognition of a thing, and packs all the things belonging to the object together; Through the access qualifier, some of its functions are selectively opened to interact with other objects. For some implementation details inside the object, external users do not need to know, and it is useless in some cases. On the contrary, it increases the difficulty of use or maintenance and complicates the whole thing.

Let's take an example to better understand the benefits of encapsulation, such as traveling by train

Let's look at the railway station:
Ticketing system: responsible for ticketing - users enter with tickets and take their seats according to the number

Staff: ticket sales, consultation, security inspection, security, sanitation, etc

Train: take the user to the destination

With the cooperation of all the staff in the railway station, we can take the train in an orderly manner. We don't need to know the structure of the train and how the ticketing system operates, as long as it can be applied normally and conveniently.
Think about it. What about an open platform without any management? There is no fence in the railway station, the management and dispatching of trains in the station are also random, and there are no rules for taking trains, such as:

7, Understand object-oriented again

Topics: C++ Back-end