Classes and objects [4] static members, const objects, friends

introduction

Through the previous three articles, I believe that everyone has a basic understanding of classes and objects.
Class and object 1 (initial knowledge)
class and object 2 (default member function)
class and object 3 (initialization list)
, but it is not difficult to find some loopholes and many points that can be improved in some of the previous examples:

For example, sometimes we need some global variables to manage the properties of many objects, but creating global variables affects class encapsulation;
we know that the type of this pointer is T* constsometimes we need to assign values ​​to other objects, such as const-modified class objects, During operations such as printing. The transfer of this pointer will cause the problem of privilege amplification;
we sometimes need to access private members outside the class, which is obviously not allowed under normal circumstances.

In this article, we will continue to supplement the knowledge of classes and objects:

static member

We know that class objects are stored in the stack area, we can calculate the size of a simple class:

class A
{
    
    
private:
	char _a;
	int _b;
	int _c;
};
int main()
{
    
    
	A a;
	cout << sizeof(a) << endl;
	return 0;
}

insert image description here
According to the memory alignment, it is not difficult to calculate that the size of this class A is 12 bytes.
These three member variables _a, _b, and _c are attributes belonging to an object, and are defined when the class is instantiated. Of course, it cannot be accessed outside the class, nor does it have global properties.

static member variable

But the static variable is stored in the static area. Although it is encapsulated in the class (only declared in the class type), it does not belong to an object.
For a class type, the static member is only declared in the class and defined outside the class. The static keyword is not added when defining, and it does not occupy the space of this type of object :

class A
{
    
    
private:
	char _a;
	int _b;
	int _c;
	static int a;
};
int A::a = 10;

int main()
{
    
    
	A a;
	cout << sizeof(a) << endl;
	return 0;
}

insert image description here
This static member variable is similar to a global variable encapsulated in a class. Although it cannot be accessed outside the class, it can play a similar role as a global variable in the class to reflect the properties of many objects of this class type.

static member function

A member function decorated with static is called a static member function:

A static member function is different from a general member function in that it does not have an implicit this pointer to pass parameters, so it cannot access private member variables. But it can access static member variables normally :

class A
{
    
    
public:
	static void fun()
	{
    
    
		//_a++; 错误代码:非静态成员引用必须与特定对象相对
		cout << a++ << endl;
	}
private:
	char _a;
	int _b;
	static int a;
};
int A::a = 10;

When accessing a static member function, you can 对象名.函数调用access it or 类类型名::函数调use it :

class A
{
    
    
public:
	static void fun()
	{
    
    
		//_a++; 错误代码:非静态成员引用必须与特定对象相对
		cout << a++ << endl;
	}
private:
	char _a;
	int _b;
	static int a;
};
int A::a = 10;

int main()
{
    
    
	A a;
	a.fun();
	A::fun();
	return 0;
}

insert image description here
As mentioned before, calling a member function is actually calling the member function instead of an object. There is a premise here, that is, when calling a member function, there must be an object body that has already been defined, so it is of course possible for general member functions to implicitly pass this pointer to access private member variables;

But for the static member function, when we call the static member function, there is no premise that the object has been instantiated (it can be called by the type name). So you can't implicitly pass this parameter, and naturally you can't access private member variables. Although the static member variable is declared in the class, it is not defined with the instantiation, so it can naturally be accessed in the function after it is defined externally.

const object

In the past, we have simply implemented some member functions, such as the function of adding date to the date class, and the printing function. For normal class objects it is of course suitable:

class Date
{
    
    
public:
	Date(int year = 2023, int month = 2, int day = 10)
		: _year(year)
		, _month(month)
		, _day(day)
	{
    
    }
	int GetMonthDay(int year, int month);
	Date& AddDate(int day);
	void print();
private:
	int _year;
	int _month;
	int _day;
};
void Date::print()
{
    
    
	cout << _year << " " << _month << " " << _day << endl;
}

int main()
{
    
    
	Date d1;
	d1.print();
	return 0;
}

insert image description here
But when we instantiate a class object of const Date type, this const object cannot call the print function to print the date:

int main()
{
    
    
	Date d1;
	d1.print();
	const Date d2;
	//d2.print();  错误代码:不能将“this”指针从“const Date”转换为“Date&“
	return 0;
}

Because the type of this pointer is Date* const, when a const object is passed to this pointer that can be changed, the problem of privilege amplification will occur, which is of course not allowed.
Faced with this kind of problem, we need to add const modification to the this pointer so that its type is const Date* const. But the this pointer is implicitly passed as a parameter, so we cannot pass a const pointer in the previous way.

C++ provides a way to modify this pointer with const, that is, add const after the parameter list :

class Date
{
    
    
public:
	Date(int year = 2023, int month = 2, int day = 10)
		: _year(year)
		, _month(month)
		, _day(day)
	{
    
    }
	int GetMonthDay(int year, int month);
	Date& AddDate(int day);
	void print() const;
private:
	int _year;
	int _month;
	int _day;
};
void Date::print() const
{
    
    
	cout << _year << " " << _month << " " << _day << endl;
}

int main()
{
    
    
	Date d1;
	d1.print();  //权限缩小
	const Date d2(2023, 5, 19);
	d2.print();  //权限平移
	return 0;
}

insert image description here
In this way, the this parameter of the const object can be realized.

Tomomoto

We sometimes need to access private member functions outside the class. Friends provide a way to break through encapsulation and provide convenience .
However, excessive use of friends will definitely destroy the package, so it is not suitable to use more!

friend function

The friend function can use the friend keyword to make an externally declared function as a friend function of the class . In this way, this friend function can access the private members of the class:

class A
{
    
    
	friend void func1(A&);
private:
	int _a;
};
void func1(A& a)
{
    
    
	cout << a._a << endl;
}

have to be aware of is:

  1. Friend functions can access the private and protected members of the class, but not the member functions of the class (there is no this pointer to pass parameters) ;
  2. Friend functions cannot be modified with const;
  3. A function can be a friend function of multiple classes;
  4. The principle of calling a friend function is the same as that of a normal function ;
  5. Friend functions can be declared anywhere in the class definition , not restricted by class access qualifiers;
  6. Anywhere inside the class , add the friend modifier to declare the external function (friend is before the return value of the function declaration).

(The application of a friend function will be introduced in the next article)

friend class

Similar to a friend function, the friend keyword can also declare an external class as a friend class of a certain class. All member functions of a friend class can be friend functions of another class and can access the functions in another class. non-public members.

class A
{
    
    
	friend void func1(A&);
	friend class B;
private:
	int _a;
};
void func1(A& a)
{
    
    
	cout << a._a << endl;
}

class B
{
    
    
public:
	void func1(A& a)
	{
    
    
		cout << a._a << endl;
	}
private:
	int _b;
};

have to be aware of is:

  1. The friendship relationship is not interchangeable :
    for example, the above-mentioned class A and class B declare class B as its friend class in class A, then you can directly access the private member variables of class A in class B, but you want to access the private member variables of class A in class A Access to private member variables in class B does not work.
  2. Friend relationship cannot be transmitted :
    if C is a friend of B and B is a friend of A, it cannot be said that C is a friend of A.
  3. The friendship relationship cannot be inherited : we will introduce it in detail later.

Summarize

At this point, all the basic knowledge about classes and objects has been introduced.
Next, we will use the previous knowledge to implement a date class as an example. I believe everyone will have a better understanding of classes and objects, welcome to continue to pay attention

If you think that I did not introduce a certain part clearly or that there is a problem with a certain part, you are welcome to raise it in the comment area

If this article is helpful to you, I hope it will be connected with one click

Hope to make progress together with you

Guess you like

Origin blog.csdn.net/weixin_73450183/article/details/130773832