[C++] Introduction to C++ Part 1 -- Namespace, input and output, default function, underlying principle of function overloading

Table of contents

1. Keywords 

2. Namespace

2.1 Definition of Namespace

2.2 How to use the namespace

2.2.1 Add namespace name and scope qualifier

2.2.2 Use using to introduce a member in the namespace

2.2.3 Import using using namespace namespace name

3. C++ input and output

4. Default parameters

4.1 The concept of default parameters

4.2 Classification of default parameters

4.2.1 All default parameters

4.2.2 Semi-default parameters

5. Function overloading

5.1 Concept of function overloading

5.2 C++ supports the principle of function overloading -- name mangling (name Mangling)


1. Keywords 

C++ has a total of 63 keywords, and C language has 32 keywords. The following figure shows the keywords of C++. We will not go into details now, we will use it later, keep paying attention, and we will explain it in use.

2. Namespace

Let's write a C++ code first, let's take a look.

#include <iostream>
using namespace std;

int main()
{
    cout << "Hello world!" << endl;
    
	return 0;
}

The first sentence #include <iostream> in this code is the same as #include <stdio.h> in C language. It is the header file to be included when calling the input and output library functions. In C++, it is also possible to use the latter. C++ is fully compatible with C language.

After understanding the input and output header files, we found that there is a second sentence using namespace std;, what is this for?

The keyword namespace is the namespace, which is an optimization of some problems in the C language. Let's look down for the specifics.

In C, we know there is a problem with naming conflicts

#include <stdio.h>
int main()
{
	int a = 10;
	int a = 20;
	
	printf("%d %d", a, a);
	return 0;
}

The problem here is redefinition, which is naming conflict. But if we are at work, and multiple programmers in a group are developing at the same time, there will definitely be naming conflicts.

C++ introduces the concept of namespace namespace.

2.1 Definition of Namespace

To define a namespace, you need to use the namespace keyword , followed by the name of the namespace , and then a pair of {} , which are members of the namespace.

Let's write a namespace code here.

namespace lcx //命名空间名字叫lcx
{
	int a = 10;//成员变量

	int Add(int x, int y)//成员函数
	{
		return x + y;
	}
}

The name of this namespace is lcx, a is a member variable of the namespace, and Add is a member function of the namespace.

Namespaces can also be nested:

namespace l1
{
	int a = 10;
	int b = 20;
	namespace l2
	{
		int a = 30;
		int b = 40;
	}

}

operation result:

In the same project, there can be multiple namespaces with the same name, and the compiler will finally synthesize a namespace:

namespace l1
{
	int a = 10;
}
namespace l1
{
	int b = 40;
}

Here, the two l1s will eventually be merged into one namespace, so variables with the same name cannot be defined in two namespaces with the same name, and conflicts will occur.

operation result:

Note: A namespace defines a new scope , and all content in the namespace is limited to that namespace.

2.2 How to use the namespace

How to use the variables and functions defined in the namespace?

2.2.1 Add namespace name and scope qualifier

namespace lcx
{
	int a = 10;

	int Add(int x, int y)
	{
		return x + y;
	}
}

Now we want to print a and call the Add function, here we need to use the scope qualifier ::, namespace name + this symbol + variable name/function name , then we can use the variable/function of the namespace.

Example: Let's print the variable a of the above code and call the function Add.

namespace lcx
{
	int a = 10;

	int Add(int x, int y)
	{
		return x + y;
	}
}
int main()
{
	int ret = lcx::Add(2, 3);

	cout << lcx::a << " " << ret << endl;

	return 0;
}

operation result:

2.2.2 Use using to introduce a member in the namespace

namespace lcx
{
	int a = 10;
	int b = 20;

	int Add(int x, int y)
	{
		return x + y;
	}
}

If we use the variable a many times in our usual practice, and use lcx::a every time we print, it is too troublesome to print, we can use using + namespace name + :: + variable name, so that a certain A variable, when used later, does not need to be written in the form of lcx::a.

namespace lcx
{
	int a = 10;
	int b = 20;

	int Add(int x, int y)
	{
		return x + y;
	}
}
using lcx::a;
int main()
{
	cout << a << " " << lcx::b << endl;

	return 0;
}

operation result:

2.2.3 Import using using namespace namespace name

When we output the value of a certain variable, we use cout and input cin, which are actually library functions that have been written by others, so we can use them directly.

In the process of our usual practice, we will use cin and cout a lot, so we will directly expand the namespace containing these two functions at the beginning, and use them directly later.

using namespace std;
int main()
{
	int a = 10;
	int b = 20;
	cout << a << " " << b << endl;

	return 0;
}

We use cout and endl when printing the local variables a and b here. These are functions of the namespace of the C++ standard template library, so we directly expand the namespace of the standard template library when we practice.

using namespace std;

std is the C++ Standard Template Library namespace.

3. C++ input and output

Let's briefly learn about the input and output of C++ here, first learn how to use it, and then we will specifically learn about the input and output streams.

Let's take a look at the code:

#include <iostream>
using namespace std;
int main()
{
	int a = 0;
	float b = 0.0f;

	cin >> a >> b;//输入多个
	cout << a << " " << b << endl;//输出多个

	return 0;
}

Here we know that cin and cout are input and output respectively, so what are the two symbols >> and <<?

In C++, >> is a stream extraction operator, << is a stream insertion operator, and both input and output can have multiple inputs and multiple outputs. endl is '\n' in C language, which means newline.

illustrate:

1. When using the cout standard output object (console) and the cin standard input object (keyboard), you must include the < iostream > header file and use std according to the usage method of the namespace.
2. cout and cin are global stream objects, and endl is a special C++ symbol that represents newline output. They are all included in the header file containing <iostream>.
4. It is more convenient to use C++ for input and output, and does not need to manually control the format like printf/scanf input and output. The input and output of C++ can automatically identify the variable type. Just like the above code, when we input, we directly use cin>>a>>b instead of using %d and %f.
5. In fact, cout and cin are objects of type ostream and istream respectively. >> and << also involve operator overloading and other knowledge. We will learn this knowledge later, so we just simply learn how to use them here. Later we will have a chapter to learn more about the usage and principle of IO flow.

4. Default parameters

4.1 The concept of default parameters

There is no default parameter in C language, what are the default parameters in C++?

The default parameter is to specify a default value for the parameter of the function when declaring or defining the function . When calling this function, if no actual parameter is specified, the default value of the formal parameter is adopted, otherwise the specified actual parameter is used.

Let's take a look at an example:

void func(int n = 10)
{
	cout << n << endl;
}
int main()
{
	func();  //不传参数的时候,使用func函数形参的默认值
	func(1); //传参数,使用实参

	return 0;
}

In this code, we did not pass parameters when calling the func function for the first time. In C language, this will report an error, but C++ supports this, because if the formal parameters of the function have default values, the calling function does not pass parameter, the default value of the formal parameter will be used. But when we call the function, we pass the actual parameters, then the actual parameters will prevail. Wickedly speaking, the default parameters are like a spare tire.

4.2 Classification of default parameters

4.2.1 All default parameters

The full default parameter means that each formal parameter of the function has a default value, so when calling the function, there is no need to pass actual parameters. If you want to pass actual parameters, you must pass them sequentially from left to right. But when passing parameters, you can't pass them skipping, for example, as follows:

void func(int a = 10, int b = 20, int c = 30)
{
	cout << a << " " << b << " " << c << endl;
}
int main()
{
	func(1);        //可以传一个
	func(1, 2);     //可以传两个
	func(1, 2, 3);  //可以全部传
	//我们传参是从左到右依次传

	return 0;
}

operation result:

Skip and pass parameters:


The call of the C++ default function does not have the concept of skipping the pass at all, so it is not possible.

4.2.2 Semi-default parameters

Semi-default is to give default values ​​to part of multiple formal parameters, but when giving default values, they must be defaulted from right to left, and defaults cannot be skipped.

Let's write a code to see the semi-default:

//半缺省
void func(int a, int b = 20, int c = 30)
{
	cout << a << " " << b << " " << c << endl;
}
int main()
{
	func(1);        //第一个必须传
	func(1, 2);     //第二个可以传,可以不传
	func(1, 2, 3);  //后两个都是可传,可不传
	//我们传参是从左到右依次传

	return 0;
}

operation result:

We can see that in the above code, the first formal parameter a of the func function we wrote is not given a default value, so the first parameter must be passed when calling, and an error will occur if it is not passed.

After learning the default parameters, what is its use?

In the stack, when we use it, we already know that when we want to open up 1000 spaces in advance, we can use the default parameters to write.

struct Stack
{
	int* a;
	int size;
	int capacity;
};

void StackInit(Stack* ps, int n = 4)
{
	assert(ps);
	ps->a = (int*)malloc(sizeof(int) * n);
	if (NULL == ps->a)
	{
		perror("malloc fail:");
		return;
	}

	ps->size = 0;
	ps->capacity = n;
}

int main()
{
	Stack st;
	StackInit(&st, 1000);

	return 0;
}

Here we use semi-default parameters. If we just initialize but don’t know how much space is suitable, we can choose not to pass it. Only 4 spaces will be opened during initialization, and there will be no waste. This is the flexible use of default parameters.

5. Function overloading

5.1 Concept of function overloading

Function overloading : It is a special case of functions. C++ allows several functions with the same name to declare similar functions in the same scope . These functions with the same name have different formal parameter lists ( parameter number or type or type order ), which are often used to deal with Implementing functions is similar to the problem of different data types.

a. We can call functions with different parameter types but with the same function name.

int Add(int x, int y)
{
	return x + y;
}
double Add(double x, double y)
{
	return x + y;
}
int main()
{
	cout << Add(1, 2) << endl;
	cout << Add(1.1, 2.2) << endl;

	return 0;
}

operation result:

In the above code, we can see that although their names are all Add, the types of parameters are different. The actual parameters we pass in when calling will call functions with the same name but different types according to the type, so different types constitute a heavy load.

b. It is also possible to call the function according to the different order of the formal parameter types but the same function name.

void func(int x, double y)
{
	cout << "void func(int x, double y)" << endl;
}
void func(double x, int y)
{
	cout << "void func(double x, int y)" << endl;
}
int main()
{
	func(1, 1.1);
	func(1.1, 1);

	return 0;
}

operation result:

The formal parameters of the two func functions here are both an integer type and a floating point type, but the order of the two formal parameters is different. When the function is called, the passed actual parameter will be called according to the type when it is not used. Different functions, and therefore different order of parameters, constitute overloading.
c. The number of parameters is different, but the function name is the same to call the function.

void func(int x, double y)
{
	cout << "void func(int x, double y)" << endl;
}
void func(int x, double y, int z)
{
	cout << "void func(int x, double y, int z)" << endl;
}
int main()
{
	func(1, 1.1);
	func(1.1, 1, 2);

	return 0;
}

operation result:

The number of parameters here is different, the first function has two parameters, and the second function has three parameters. The number of parameters passed when calling is different, and the function to be called is also different. Therefore, the different number of parameters constitutes a function repetition . load.

After writing this, some people will definitely think, can different return value types also constitute overloading?

Let's answer first: no. Let's verify it:

short func(short x, short y)
{
	return x + y;
}
int func(short x, short y)
{
	return x + y;
}

It can be seen here that different return types cannot constitute overloading.

Summary: Under the premise of the same function name, the types of parameters are different, the order of parameters is different, and the number of parameters is different. These three cases can constitute function overloading.

5.2 C++ supports the principle of function overloading -- name mangling (name Mangling)

Why does C++ support function overloading, but C language does not support function overloading?
In C/C++, a program needs to go through four stages to run: preprocessing, compiling, assembling, and linking.

The processes of these four stages are (in terms of Linux process):

1. Preprocessing: header file expansion, macro replacement, comment removal, conditional compilation, and generation of test.i

2. Compile: check syntax, generate assembly (instruction-level code), and generate test.s

3. Assembly: convert the assembly code into binary machine code and generate test.o

4. Link: merge link, generate executable program, a.out

C++ function overloading is mainly to use the name of the function to find the address when linking, and the same is true in C language. But C++ introduces the function name modification rules, which is the fundamental reason why C++ supports function overloading. Let's start with the Linux environment.

We have written two functions here to form function overloading.

Under Linux, g++ has its own set of function name modification rules, let's take a look.

Combining the above two screenshots, we can conclude that the function name modification rules under g++ are:

_Z The length of the function name The first letter of the function name formal parameter

Therefore, even if the function names are the same, but different types, different orders, and different numbers will produce different function names.

When the function is called, the instruction is the call function name, and the modified function name will find the address of the corresponding function after jumping, so that the corresponding function can be found. This is why after the function name modification rules are modified, the corresponding function name is found in the symbol according to different function names, and the corresponding address is found, and finally jumps to the reason to call the corresponding function.

The reason why the C language does not work is that there is no function name modification rule like C++. Its function name is directly stored in the symbol table. If it is the same function name, it will be messed up as soon as it enters the symbol table. The first letter distinguishes functions in this way, so C language cannot implement function overloading.

Guess you like

Origin blog.csdn.net/Ljy_cx_21_4_3/article/details/131889153