C + + 3 | static members and friends

Posted by simonp on Thu, 10 Feb 2022 16:13:08 +0100

3, Static members and friends

1. Constant (const is used in C + + as in C language)

class A{
    public:
    	A():x(100){}
    	const int x;//Constant data member
    	void func() const;//Constant member function
    	const A a;//Constant object
}

Example 9. Parameter passing characteristics of constant member functions and constructors

#include <stdio.h>

class A{
	public:
		A(int data = 0,int a = 1):b(data){//Initialization table writing method
            //Generally, when the parameter data is assigned to B, b=data is written in {}; But here B is a constant (const int b), so it can only be written as: b(data). For convenience, it is uniformly written as: b(data).
			this->a = a;//A modified by this is the following private member int a, and this is used to distinguish a passing parameters
			printf("AAAAAAAAA\n");
		}
		~A(){
			printf("~~~~~~~~~\n");
		}

		void show(void) const
		{
			printf("a = %d\n", a);
			printf("b = %d\n", b);
		}
	private:
		int a;
		const int b;
};

int main()
{
	A x(6);
	x.show();

	A y(7);
	y.show();

	A z;
	z.show();
}

result:

@ubuntu:/mnt/hgfs/ub2/class$ g++ const.cpp 
@ubuntu:/mnt/hgfs/ub2/class$ ./a.out 
AAAAAAAAA
a = 1
b = 6
AAAAAAAAA
a = 1
b = 7
AAAAAAAAA
a = 1
b = 0
~~~~~~~~~
~~~~~~~~~
~~~~~~~~~
@ubuntu:/mnt/hgfs/ub2/class$ 

According to the results, it is found that the value of a has always been the default value of 1, because A x(6); 6 is passed to data, then assigned to b, and finally printed out b. The constructor passes parameters in sequence, and data comes first, so the parameters are assigned to data.

2. Static member (belonging to class but not object)

static int x;
static const int x = 10;
static int A::x = 10;//Out of class
static void func();
A::func();//Out of class call

Example 10: accessing class members without objects

#include <stdio.h>

class A{
	public:
		void func(void)
		{
			printf("xxxxxxxxx\n");
		}
};

int main()
{
	A a;
	a.func();
}

The above shows the general function usage: first create an object a, and then a accesses the function func().

However, sometimes you want to access class member functions without creating objects, so you can write as follows:

A::func();

So there are:

#include <stdio.h>

class A{
	public:
		void func(void)
		{
			printf("xxxxxxxxx\n");
		}
};

int main()
{
	A a;
	a.func();
	A::func();
}

Result error:

@ubuntu:/mnt/hgfs/ub2/class$ g++ static_1.cpp 
static_1.cpp: In function 'int main()':
static_1.cpp:15:10: error: cannot call member function 'void A::func()' without object
  A::func();
          ^
@ubuntu:/mnt/hgfs/ub2/class$

The error is that ordinary member functions need to create objects first, and then access class member functions according to objects. Static member functions can be accessed without objects. Generally speaking, ordinary member functions reject single dogs (so static is fragrant).

After changing to static member function, it is as follows:

#include <stdio.h>

class A{
	public:
		static void func(void)
		{
			printf("xxxxxxxxx\n");
		}
};

int main()
{
	A a;
	a.func();
	A::func();
}

result:

@ubuntu:/mnt/hgfs/ub2/class$ g++ static_1.cpp
@ubuntu:/mnt/hgfs/ub2/class$./a.out
xxxxxxxxx
xxxxxxxxx
@ubuntu:/mnt/hgfs/ub2/class$

This is true for member functions and for members of other data types, such as static int data:

#include <stdio.h>

class A{
	public:
		static void func(void)
		{
			printf("xxxxxxxxx\n");
		}

		static int data;
};

int A::data = 0;//Static members need to be initialized (outside the class)

int main()
{
	A a;
	a.func();
	A::func();
//General situation
	A x;
	x.data = 6;
	printf("x.data = %d\n", x.data);

//No object
	A::data = 7;
	printf("A::data = %d\n", x.data);
}

result:

@ubuntu:/mnt/hgfs/ub2/class$ g++ static_2.cpp
@ubuntu:/mnt/hgfs/ub2/class$./a.out
xxxxxxxxx
xxxxxxxxx
x.data = 6
A::data = 7
@ubuntu:/mnt/hgfs/ub2/class$

3. Friend (destroy package)

At first, we bundled and encapsulated them for security, but later we found that in some cases, we still need to make targeted operation changes to the members in the package, so we need friends to make the originally private ones can be used under specific circumstances.

friend class B;//Friend class
friend void func();//friend function
friend void B::func();//friend member function 

Before talking about friends, let's review a previous case:

Example 11-1: adding data at the end of the array (review)

arr.h

#ifndef _ARR_
#define _ARR_


class ARR{
public:
	ARR():tail(0){
	}

	void addtail(int data);
	void show(void);
	
private:
	int data[100];
	int tail;
};


#endif

arr.cpp

#include "arr.h"
#include <stdio.h>


void ARR::addtail(int data)
{
	this->data[tail++] = data;
}

void ARR::show(void)
{
	int i = 0;
	for(;i<tail; i++)
		printf("%d, ", data[i]);
	printf("\n");
}

main.cpp

#include "arr.h"

int main()
{

    ARR arr;

    arr.addtail(1);
    arr.addtail(2);
    arr.addtail(5);
    arr.addtail(8);
    arr.addtail(0);
    arr.show();
    
}

result:

@ubuntu:/mnt/hgfs/ub2/ARR4$ ls
arr.cpp  arr.h  main.cpp
@ubuntu:/mnt/hgfs/ub2/ARR4$ g++ *.cpp
@ubuntu:/mnt/hgfs/ub2/ARR4$ ./a.out 
 1, 2, 5, 8, 0, 
@ubuntu:/mnt/hgfs/ub2/ARR4$ 

Now I want to reverse the above data (become 08521). So try the following:

For main C amend to read

#include "arr.h"
void rev(ARR &arr)
{
    int i = 0;
    for(;i<arr.tail/2;i++)
    {
        int tem = arr.data[i];
        arr.data[i] = arr.data[tail-i-1];
        arr.data[arr.tail-i-1] = tem;
    }
}

int main()
{

    ARR arr;

    arr.addtail(1);
    arr.addtail(2);
    arr.addtail(5);
    arr.addtail(8);
    arr.addtail(0);
    arr.show();
    
    rev(arr);
	
    arr.show(); 
}

Result error:

@ubuntu:/mnt/hgfs/ub2/ARR4$ ls
arr.cpp  arr.h  main.cpp
@ubuntu:/mnt/hgfs/ub2/ARR4$ g++ *.cpp
In file included from main.cpp:1:0:
arr.h: In function 'void rev(ARR&)':
arr.h:15:6: error: 'int ARR::tail' is private
  int tail;
      ^
main.cpp:6:16: error: within this context
     for(;i<arr.tail/2;i++)
                ^
In file included from main.cpp:1:0:
arr.h:14:14: error: 'int ARR::data [100]' is private
  int data[100];
              ^
main.cpp:8:23: error: within this context
         int tem = arr.data[i];
                       ^
In file included from main.cpp:1:0:
arr.h:14:14: error: 'int ARR::data [100]' is private
  int data[100];
              ^
main.cpp:9:13: error: within this context
         arr.data[i] = arr.data[arr.tail-i-1];
             ^
In file included from main.cpp:1:0:
arr.h:14:14: error: 'int ARR::data [100]' is private
  int data[100];
              ^
main.cpp:9:27: error: within this context
         arr.data[i] = arr.data[arr.tail-i-1];
                           ^
In file included from main.cpp:1:0:
arr.h:15:6: error: 'int ARR::tail' is private
  int tail;
      ^
main.cpp:9:36: error: within this context
         arr.data[i] = arr.data[arr.tail-i-1];
                                    ^
In file included from main.cpp:1:0:
arr.h:14:14: error: 'int ARR::data [100]' is private
  int data[100];
              ^
main.cpp:10:13: error: within this context
         arr.data[arr.tail-i-1] = tem;
             ^
In file included from main.cpp:1:0:
arr.h:15:6: error: 'int ARR::tail' is private
  int tail;
      ^
main.cpp:10:22: error: within this context
         arr.data[arr.tail-i-1] = tem;
                      ^
@ubuntu:/mnt/hgfs/ub2/ARR4$

The error message includes:

arr.h:15:6: error: 'int ARR::tail' is private
arr.h:14:14: error: 'int ARR::data [100]' is private

Indicates that access to private members was denied when crossing the border. If you don't want access denied in this case, you need to apply the function as a friend in the class. (of course, you can also classify this function into a class as a static member function and call it through the class)

Example 11-2. Reverse order (from back to front, not sorting)

arr.h

#ifndef _ARR_
#define _ARR_


class ARR{
public:
	ARR():tail(0){
	}

	void addtail(int data);
	void show(void);
	
    friend void rev(ARR &arr);//Mark the rev function as a friend
	
private:
	int data[100];
	int tail;
};


#endif

arr.cpp

#include "arr.h"
#include <stdio.h>


void ARR::addtail(int data)
{
	this->data[tail++] = data;
}

void ARR::show(void)
{
	int i = 0;
	for(;i<tail; i++)
		printf("%d, ", data[i]);
	printf("\n");
}

main.cpp

#include "arr.h"

void rev(ARR &arr)
{
    int i = 0;
    for(;i<arr.tail/2;i++)
    {
        int tem = arr.data[i];
        arr.data[i] = arr.data[arr.tail-i-1];
        arr.data[arr.tail-i-1] = tem;
    }
}

int main()
{

    ARR arr;

    arr.addtail(1);
    arr.addtail(2);
    arr.addtail(5);
    arr.addtail(8);
    arr.addtail(0);
    arr.show();
    
    rev(arr);
	
	arr.show(); 
    
}

result:

@ubuntu:/mnt/hgfs/ub2/ARR5$ ls
arr.cpp  arr.h  main.cpp
@ubuntu:/mnt/hgfs/ub2/ARR5$ g++ *.cpp
@ubuntu:/mnt/hgfs/ub2/ARR5$ ./a.out 
1, 2, 5, 8, 0, 
0, 8, 5, 2, 1, 
@ubuntu:/mnt/hgfs/ub2/ARR5$

After the keyword friend is marked, you can access private members.

Example 11-3: friend class members (members of class B become friends of class A, and then members of class B can access private members of class a)

First, class a creates an object x to access the private member y (A x; x.y), and then creates a member function printfA() in class B to print the private member y of object x of class A. Therefore, class B can create an object B, and then print the private member y of class a through its member function (b.printfA(a);). Generally, only one of its members, such as void printfa (a &x), needs friendliness, while other members of class B do not. Therefore, it is inappropriate to apply for the whole class B as a friend.

#include <stdio.h>

class A;//Attention should be paid to the existence here, because I deliberately make the case that there are friends of class B in class A, and the member functions of class B use class A.
//You have me in you and I have me in you. You need such a duplicate logo.

class B{
public:
	void printfA(A &x);	
};

class A{
public:
	A()
	{
		y = 100;
	}

//	friend class B;// This sentence is a direct one size fits all friendliness of the whole class
	friend void B::printfA(A &x);//It is only friendly for a member function in class B
private:
	int y;
};


void B::printfA(A &x)
{
	printf("%d\n", x.y);
}

int main()
{

	A a;
//	printf("%d\n", a.x);

	B b;
	b.printfA(a);
}

result:

@ubuntu:/mnt/hgfs/ub2$ g++ friend.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out 
100
@ubuntu:/mnt/hgfs/ub2$

Topics: C++