[C + + from getting started to kicking the door] Chapter 1: getting to know C++

Keywords: C++


1. The origin of C + +

For complex problems, large-scale programs that require a high degree of abstraction and modeling, C language is not appropriate. In order to solve the software crisis, in the 1980s, the computer community put forward the idea of OOP (object-oriented programming), and the object-oriented programming language came into being.

In 1982, Dr. Bjarne Stroustrup introduced and extended the concept of object-oriented on the basis of C language and invented a new programming language. In order to express the origin relationship between the language and C language, it is named C + +. Therefore, C + + is based on C language. It can not only carry out procedural programming of C language, object-based programming characterized by abstract data types, but also object-oriented programming.

2.C + + keywords

C + + has 63 keywords, about twice as many as the 32 keywords of C language.

3.C + + namespace

Functions and some variables exist in the global scope. Avoid duplicate name conflicts caused by function names and variable names in the process of gradually expanding the project in the future.
The purpose of using namespaces is to localize the name of identifiers, declare in their own named space, and define functions and variables to prevent duplicate names.

3.1 definition of namespace

a. Common use

namespace Mine //Keyword -- namespace name -- Mine
{
	//Define variables
	int time;
	//Define function
	void Func()
	{
		printf("namespace Mine\n");
	}
	//Define structure type
		struct Node
	{
		struct Node* next;
		int data;
	};
}

b. Namespaces can be nested

namespace Mine
{
	//Define variables
	int time = 0;
	//Define function
	void Func()
	{
		printf("namespace Mine\n");
	}
	//Define type
	struct Node
	{
		struct Node* next;
		int data;
	};
	namespace Mine2
	{
		void Func()//Note that the name of the function here is exclusive to Mine2. Even if it is nested in the space of Mine, there will be no conflict
		{
			printf("namespace Mine2\n");
		}
	}
}

Note: a namespace defines a new scope, and all contents in the namespace are limited to the namespace

c. What if the namespace names conflict?
Multiple namespaces with the same name will be merged into one namespace at compile time, but variables or function names with the same name under the same namespace will still cause conflicts!

//In the source.h file
namespace myspace
{
	int rand;
	double Add(double a, double b);
	int Mul(int a, int b);
}
//In the source.c file
namespace myspace
{
	//int rand;// Conflicts will occur here and should be avoided
	double Add(double a, double b)//Function overloading is possible
	{
		return a + b;
	}
	
	int Mul(int a, int b)
	{
		return a * b;
	}
}


namespace with the same name is mostly used for declarations in header files and definitions in source files.

3.2 use of namespace

  • Method 1: add namespace name and scope qualifier (:)
int main()
{
	Mine::time = 10;
	printf("%d\n", Mine::time);
	Mine::Func();
	Mine::Mine2::Func();

	return 0;
}

  • Method 2 - use using to release some members in the namespace that can be used directly, but at the same time, the released members lose isolation, which may conflict with some quantities in the global scope!
using Mine::Mine2::Func;//Func in Mine2 has been released and can now be used directly
int main()
{
	Func();
	return 0;
}


If Mine's Func is released at the same time

using Mine::Func;
using Mine::Mine2::Func;
int main()
{
	Func();
	return 0;
}

There was a conflict

Function overloading is discussed below.

  • Method 3: use namespace + space name to introduce all the names of the namespace into the global scope
using namespace Mine;
int main()
{
	Func();
	Mine2::Func();
	return 0;
}

4.C + + input and output

The first call of C + +

#include <iostream>
using namespace std;
int main()
{
	cout<<"Hello world!"<<" "<<"from CPP"<<endl;
	return 0;
}

When using cout standard output (console) and cin standard input (keyboard), the < iostream > header file and std standard namespace must be included.

int main()
{
	int a;
	double b;
	cin>>a>>b;
	cout<<a<<" "<<b<<endl;
}

  • Symbols > > and < < indicate data input and output to the stream
  • endl(end line) indicates a line break.
  • It is more convenient to use C + + input and output without adding data format control, such as floating point –% f, string –% s.

5. Default parameters

5.1 understanding default parameters

When declaring or defining a function, set the default value for the parameters of the function. When calling a function, if no argument (default argument) is specified, the default value is used as the parameter.

void Func(int a=0)
{
	cout<<a<<endl;
}
int main()
{
	Func();
	Func(10);
	return 0;
}

5.2 default parameter classification

  • All default parameters
void Func1(int a = 1, int b = 2, int c = 3)
{
	cout <<"a="<< a << " ";
	cout <<"b="<< b << " ";
	cout <<"c="<< c << endl<<endl;
}

Arguments are given to formal parameters from left to right

  • Semi default parameter
    Default partial parameters – must be defaulted from right to left and must be continuously defaulted
void Func2(int a,int b=1,int c=2)
{
	cout <<"a="<< a << " ";
	cout <<"b="<< b << " ";
	cout <<"c="<< c << endl<<endl;
}

  • Note that default parameters cannot appear in both function declarations and definitions
//source.h
void TestFunc(int* a,int n=10 );

//source.c
void TestFunc(int *a,int n=10)
{} 


If the definition and declaration have default values at the same time, the default values provided happen to be different, which will cause ambiguity to the compiler.

  • The default value must be a constant or a global variable

6. Function overloading

6.1 function overload concept

If several functions in the same scope have the same name but different parameter lists (different number, order and type of parameters), we call them overloaded functions.

Refer to the following function declaration

void print(const char *cp);
void print(const int* beg,const int* end);
void print(const int ia[],size_t size);

These functions accept different formal parameters. The compiler will infer which function you want according to the actual accepted argument types.

int a[2]={0,1};
int b[2]=[8,9];
print("hello world");//Call void print(const char *cp);
print(a,2);//Call void print(const int ia[],size_t size)
print(a,b);//Call void print(const int ia[],size_t size);
  • Note that the main function cannot be overloaded
  • Function overloading and default parameters
void f()
{
	cout<<"f()"<<endl;
}
void f(int a=0)
{
	cout<<"f(int a)"<<endl;
}

Note that the above two functions are overloaded because the parameters are different. However, it will cause ambiguity when used.
When passing parameters, the compiler can distinguish two functions, but no error will be reported.

6.2 function overload principle (optional reading)

There are several stages in running a program:

  • Preprocessing, compilation, assembly, linking
    We use the gcc compiler of linux to compile the following programs, taking the compiler test.c as an example:
    gcc -E -- preprocessing, generated file test.i
    gcc -S -- compile and generate assembly code, and the generated file is test.S
    gcc -c -- assemble the generated machine code and generate the file test.o
    gcc -- execute the link to generate an executable named a.out by default
    Illustration:


1. Many of our projects are composed of multiple header files and source files. In the preprocessing stage, the header files are expanded in the included source files. When the source files are compiled, they can only obtain the function declaration [test.o calls the Add function, but there is no function definition of Add], and the real Add function is defined in sum.o.
2. The linker sees that test.o calls Add, but Add has no address, so it finds the address of Add in the symbol table of sum.o and links it together.
3. How does the symbol table describe the function?
The results we see when compiling with gcc (C language compiler) are as follows:

Obviously, when compiling C language, the symbol table directly records the function name. Even if the parameters of the same function name are different, the compiler will not recognize it. Therefore, function overloading can not be used in C naturally,
Let's try again with g + + (C + + compiler):

After modifying the function of g + +, it becomes [_Z + function length + function name + type initials]. The modification of the function name changes. After the function parameter type information is added to the modified name, even if it is a function with the same name, which one is used can be judged by the difference of parameters. Therefore, we understand that function overloading requires different parameters, which has nothing to do with the return value!

7. Reference (lvalue reference)

7.1 quoted concepts

Reference has another name for the object. The compiler will not open up memory space for the referenced variable. It shares a memory space with the variable it references.

Type & reference variable name = reference entity;

int val=10;
int& refval=val;//refval refers to Val, which is another name of val
int& refval2;//Error, reference must be initialized

Generally, when initializing a variable, the initial value will be copied to the variable. However, when defining a reference, the program binds the reference to its initial value instead of copying the initial value to the reference. Once initialization is completed, the reference will always be bound to the initial value.
Assigning a value to a reference actually assigns the value to the object bound to it.
Cannot rebind a reference to another object, so the reference must be initialized

A reference is not an object, it's just an alias for an existing object

Taking the reference as the initial value is actually taking the bound object as the initial value.

int& refval3=refval;//Yes, this is bound to val
int i=refval;//Correct, i is initialized to the value of val

&Is the identifier of the reference. Multiple references are defined in one line, and each name needs to start with &

int i1=10,i2=20;
int &r1=i1,&r2=i2;

7.2 reference usage scenarios

The value of reference is reflected in the parameter passing and value return in the function call.
There are copies of both:

1. Make parameters

A reference has the same value as a pointer when it is a function parameter

a. If the array of arguments is large, all arrays will be copied by passing values, and a lot of copying time can be saved by passing pointers and References:

struct A
{
	int arr[100000];
};

void func1(struct A a)//Value transmission
{}

void func2(struct A* a)//Byref 
{}

void func3(struct A& a)//Pass reference
{}


int main()
{
	A a;
	int begin1 = clock();
	for (int i = 0; i < 1000; i++)
	{
		func1(a);
	}
	int end1 = clock();

	int begin2 = clock();
	for (int i = 0; i < 1000; i++)
	{
		func2(&a);
	}
	int end2 = clock();

	int begin3 = clock();
	for (int i = 0; i < 1000; i++)
	{
		func3(a);
	}
	int end3 = clock();

	printf("Value transfer time:%d\n", end1-begin1);
	printf("Pointer transfer time:%d\n", end2 - begin2);
	printf("Time consuming for reference:%d\n", end3 - begin3);
}

b. The modification of formal parameters can affect the actual parameters (output parameters)

2. Return value

a. Return local variable (error)
Since the return of variables in the function scope is a copy, never return references to local variables in the function scope! The referenced object cannot be saved because the stack frame is destroyed at the end of the function.


At this time, although the reference of the function local variable can be obtained, it has caused illegal access because the function stack frame has existed in name.

When other functions are used later, the original stack frame will be overwritten, and the referenced objects will naturally be "buried" without being protected.

b. The variables that still exist in the scope can be returned by reference, such as global variables, static variables, parameter variables of external incoming functions, spatial objects of malloc, etc.

The advantage of returning a reference is that it is readable and writable, because once the reference is returned, it has the function of lvalue (which can be modified):

const int N = 10;

int& At(int i)
{
	static int a[N];
	return a[i];
}

int main()
{
	for (int i = 0; i < N; i++)
	{
		At(i) = N + i;//The return value can be assigned
	}

	for (int i = 0; i < N; i++)
	{
		cout << At(i) << endl;
	}
}

Function overload passed by reference


Reference passing can be overloaded, but it is ambiguous with value passing when calling. It is unknown whether to pass value or reference when calling.

1. Reference is used to pass parameters and return values. In some scenarios, performance can be improved (large objects + deep copy objects)
2. Reference the returned value, output type parameter and output type return value of the passed parameter. Generally speaking, the change of formal parameters can change the arguments. You can change the return object.

7.3 frequently cited

Binding a reference to a const object is called a reference to a constant.

  • Constant references bind non constant objects, literals, and general expressions

See the following error reports:

When const is added, the error message disappears

The easiest way to understand this exception is to find out what happens when a constant reference is bound to another type:

double a=1.1;
const int& ra=a;

ra is an int reference, but it is bound to a double precision floating-point number. Therefore, to ensure that ra is bound to an integer, the compiler makes the following modifications:

const int temp=a;
const int& ra=temp;

Here ra binds a temporary variable object with constancy. The so-called temporary variable object is an unnamed variable that the compiler needs a space to temporarily store the evaluation result of the expression.
The temporary variable is an R-value. The implicit type conversion, expression result and literal value it accepts have constant properties and cannot be modified, so const needs to be added.

Posted by maxic0 on Wed, 01 Dec 2021 05:33:31 -0800