C++ Basics Quick Start

Table of contents

1. Namespace

1.1 Namespace use How to use the members in the namespace?

1.2 Two other ways to use the namespace:

1. Using introduces one of the members

2. using namespace + xxx to introduce the entire namespace (use with caution - it will make the isolation invalid and cause renaming)

Two, C++ input & output (simple use)

2. 1 Header file

2.2 The characteristics and simple application of cout and cin:

 Three, the default parameters

 3. 1 Concept

 3.2 Classification of default parameters:

 3.3 Notes on characteristics

 Fourth, function overloading

4.1 Concept

4. 2-line parameter list classification

1. The parameters are different

2. Different types

3. Type order

 4.3 Why does C not support it, but C++ supports overloading?

V. Quote

 5.1 Concept 

 5.2 Citation Properties

 5.2 Usage Scenarios

1. Make parameters

2. Do the return value

 5. 3 Passing parameters, compared with the efficiency of passing references

 5.4 Common references

 5.5 The difference between references and pointers  

 5.6 Differences between references and pointers

Six, inline functions  

6.1 Features

Seven, the auto keyword (C++11)

         7.1 Thinking

7.2 Introduction to auto

7. 3 Auto usage rules

7.4 Scenarios where auto cannot be derived

 Eight, range-based for loop (C++)

8.1 Ranged for loop syntax 

8. 2 Conditions of use of scope for

Nine, pointer null value nullptr (C++11)

9.1 Pointer null in C++98

epilogue


1. Namespace

   In C/C++, there are a large number of variables, functions, and classes to be learned later. The names of these variables, functions, and classes will all exist in the global scope, which may cause many conflicts. The purpose of using namespaces is to localize the names of identifiers to avoid naming conflicts or name pollution . The appearance of the namespace keyword is aimed at this problem.
#include <stdio.h>
#include<stdlib.h>

int rand = 0;

namespace set  // 看起来有些类似于结构体,但不是结构体创建的是类型;
{
   int rand = 0;
}
int main()
{
	printf("%d\n", rand); 
    
// 运行这段代码我们会发现:rand重定义
// 原因是:预处理时会加载stdlib.h头文件代码,里面存有rand函数。
// 解决方法:1. 在C语言中我们只能改名字。
//           2. 在c++中我们可以在全局域建立命名空间,存放变量,这样就不与头文件中的名冲突。
// 使用如下:
    printf("%d\n", set::rand);
	return 0;
}

( Note : Namespaces are defined in the global variable domain , and the life cycle is the same as the static area. Namespaces just change the way the compiler looks for variables or functions , so that they are distinguished from functions and variables in header files.) 

1.1 Namespace use How to use the members in the namespace?

for example :

  • 1. Variables/functions/types can be defined.
  • 2. Namespaces can be nested.
  • 3. Between different files, the same namespace will be integrated.

The code example is as follows: 

namespace set
{
 // 1. 命名空间中可以定义变量/函数/类型
   int rand = 10;
 int Add(int left, int right)
  {
    return left + right;
   }
 // 注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
 struct Node
   {
     struct Node* next;
     int val;
   };
}


//2. 命名空间可以嵌套
// test.cpp

namespace N1
 {
    int a;
    int b;
    int Add(int left, int right)
    {
      return left + right;
    }

  namespace N2
   {
     int c;
     int d;
     int Sub(int left, int right)
     {
         return left - right;
     }
   }
}

//3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
// ps:一个工程中的test.h和上面test.cpp中两个N1会被合并成一个
// test.h
namespace N1
{
int Mul(int left, int right)
 {
     return left * right;
 }
}


1.2 Two other ways to use the namespace:

  • 1. Using introduces a member in the namespace

using N::b;
int main()
{
   printf("%d\n", N::a);   
   printf("%d\n", b);
   return 0;    
}
  • 2. Using namespace + xxx introduces the entire namespace ( possible isolation failure, naming pollution )

using namespce N;
int main()
{
       printf("%d\n", N::a);
       printf("%d\n", b);
       Add(10, 20);
   return 0;    
}

So when we first step into C++, we will find that a lot of codes like using namespace std at the beginning; this will be explained below. 

Two, C++ input & output (simple use)

2. 1 Header file

#include<iostream>           // The early compiler was #include<iostream.h>, but now the compiler does not support this way of writing.
using namespace std; // If you don't do any processing, you have to use std::cout, std::cin, and std::endl for every input and output, so it's inconvenient to write, so it's imported directly. 

Note : But this way of writing is not suitable for large projects , and it is prone to naming conflicts  . A better way of writing is to only import these two separately, as follows:

#include<iostream>

using  std::cout;

using  std::cin;

// This will avoid the introduction of other methods and prevent possible naming pollution.

2.2 The characteristics and simple application of cout and cin:

  • 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 means newline output. They are all included in the header file containing <iostream> .
  • 3. << is a stream insertion operator and >> is a stream extraction operator .
  • 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 .
  • 5. In fact, cout and cin are objects of type ostream and istream respectively . >> and << also involve operator overloading and other knowledge. Here is just a simple study of their use.
#include<iostream>
using namespace std;
int main()
{   
	int k = 10;
	int c;
	double z;
	// 1. cout
	printf("%d\n", k); // C++向下兼容C
	cout << "hello word"<< " " << k << endl;  // endl 其实等同于插入“\n”
	cout << "hello word" << " " << k << "\n";
	// 2. endl
	cin >> k >> c >> z;
	cout << k << " " << c << " " << z;
	return 0;
}

 Three, the default parameters

3. 1 Concept

         The default parameter is to specify a default value for the parameter when declaring or defining the function . When calling the function, if no actual parameter is specified, the default value of the formal parameter is adopted, otherwise the specified actual parameter is used. ( Note : The default parameter here is just to assign an initial value , do not understand it as initialization)

void Func(int a = 0)
{
 cout<<a<<endl;
}
int main()
{
   Func();     // 没有传参时,使用参数的默认值
   Func(10);   // 传参时,使用指定的实参
   return 0;
}

 3.2 Classification of default parameters:

  • 1. All default parameters
  • 2. Semi-default parameters
void Func(int a = 0, int b = 4, int z = 6)
{
	cout << a << endl;
}
int main()
{
	Func(); // 缺少全部参数----全缺参数
	Func(1); //缺少部分参数----半缺参数
    Func(2, 3);    // 填充的参数遵循从左往右
	Func(, 7, );   //  该代码会报错,可见缺省参数,也不是乱填的还得遵循一些规则
	Func(, 5, 7);  //  报错
	return 0;
}

Application scenario: Take the game as an example, moving the default key can be understood as a full default parameter , and when you modify it to the key position that suits you, it can be understood as an input parameter

 3.3 Notes on characteristics

  • 1. The semi-default parameters must be given sequentially from right to left , and cannot be given alternately.
  • 2. Default parameters cannot appear in function declaration and definition at the same time. ( Default parameters either appear in the declaration or in the definition, it is recommended to set them in the declaration)

like:

//a.h
  void Func(int a = 10);
  
// a.cpp
  void Func(int a = 20)
 {}
  
// 注意:如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该
// 用那个缺省值,因此会报错。----这里涉及函数重载,后面我们会了解

 Fourth, function overloading

4.1 Concept

In natural language, a word can have multiple meanings, and people can judge the true meaning of the word through the context, that is, the word is overloaded.

Function overloading: It is a special case of a function. C++ allows several functions of the same name with similar in the same scope . The formal parameter lists ( number of parameters or type or type order ) of these functions with the same name are different , which are often used to deal with Implementing functions is similar to the problem of different data types. (And C does not allow functions with the same name)

4. 2-line parameter list classification

1. The parameters are different

// 1、参数类型不同
int Add(int left, int right)
{
   cout << "int Add(int left, int right)" << endl;
 return left + right;
}
double Add(double left, double right)
{
   cout << "double Add(double left, double right)" << endl;
 return left + right;
}

2. Different types

// 2、参数个数不同
void f()
{
 cout << "f()" << endl;
}
void f(int a)
{
 cout << "f(int a)" << endl;
}

3. Type order

// 3、参数类型顺序不同
void f(int a, char b)
{
 cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
 cout << "f(char b, int a)" << endl;
}

 (It is worth noting that if the default parameters are different , the requirements of the overloaded function will not be met , and an ambiguity error will occur when the system calls this function.)


void Func(int a = 10 , int b = 2)
{
	cout << "Func(int a = 10 , int b = 2)" << endl;
}

void Func(int a = 2, int b = 10)
{
	cout << "Func(int a = 2, int b = 10)" << endl;
}

int main()
{
	Func();
}
//  我们运行此代码就会发现会发生报错

 

 4.3 Why does C not support it, but C++ supports overloading?

      Some knowledge of disassembly and compilation process will be used here. Here is the detailed compilation process, please move to this article. This article  is suitable for Xiaobai to learn about preprocessing and programming environment. This article is enough.

     We know that the program runs through the processes of preprocessing->compilation->assembly->linking , among which there will be situations defined in other files, etc.:

  • 1. If the function is defined in this file, the address of the function will be filled in when compiling.
  • 2. If it is only declared and defined in other files, then the address will not be filled in when compiling, but will be searched for functions in other files through the modified name of the function during linking , and if there is, then fill in the address.

   In the symbol table of the  C++ object file , the identifier of the function name is not directly used to find the function , and the decoration rules of the function name are different under different compilers. The following is carried out in Linux. 

Under linux, the modified name rule of its function is: _Z + length of function name + function name + initial letter of formal parameter 

As the following code:

// 在test.h中
void f();
void f(int a);

// 在test.c中
void f()
{
	printf("f()");
}

void f(int a)
{
	printf("f(int a)");
}

//  测试文件
int main()
{
	f();
	f(1);
	return 0;
}

The disassembly of the compiled function of the C++ program under the Linux operating system is as follows:

 The C language does not support overloading, because the function decoration name is not distinguished enough. In the compilation process, when searching from other files, the C language simply searches for the function name, so the machine cannot distinguish between functions with the same name.

The following is the disassembly in C language :

Therefore, in C++, there are relatively complicated rules for modifying function names. As long as the formal parameters are different, there will be no conflict between the two functions, and the address of calling the function when linking is also clear.

V. Quote

5.1 Concept 

     A reference is not a new definition of a variable, but an alias for an existing variable . The compiler will not open up memory space for the reference variable, and it shares the same memory space with the variable it refers to.

     Type & reference variable name (object name) = reference entity ; (note: the reference must be of the same type as the variable)

#include <iostream>
using std::cout;
using std::cin;
int main()
{
    int a = 10;
    int& b = a;
    cout << a << " " << b << "\n";
    return 0;
}

We can find that the reference has the same address as the referenced variable 

 5.2 Citation Properties

  • 1. References must be initialized at definition time
  • 2. A variable can have multiple references. (multiple names)
  • 3. Reference Once an entity is referenced, no other entity can be referenced. (In other words, once defined, it cannot be modified) (It highlights that the pointer is like a scumbag)

 5.2 Usage Scenarios

1. Make parameters

#include <iostream>
using std::cout;
using std::cin;
void swap(int& a, int& b)
{
	int tmp = b;
	b = a;
	a = tmp;
}

void j(int*& a)      // 传二级指针
{
	*a *= 2;   // 引用就是一级指针本体
}

int main()
{
	int a = 10, b = 20;
	swap(a, b);

	int z = 100;
	int* k = &z;
	j(k);     
	cout << z;
	return 0;
}

2. Do the return value

#include <iostream>
using std::cout;
using std::cin;

int func(int& a, int& b)
{
	int c = a + b;
	return c;   // 这是将c的值进行临时拷贝(一般放在寄存器中)
}

int& func2(int& a, int& b)
{
	int c = 2 * a + b;
	return c;   // 返回一个引用,出函数后通过引用再次访问(本质上是非法访问)
}

int main()
{
	int a = 1, b = 2;
	int& a1 = a, & b1 = b;
	int z = func(a1, b1);
	cout << z << "\n";
	z = func2(a1, b1);
	cout << z << "\n";
	return 0;
}

  

Note: If the function returns out of the scope of the function, if the returned object is still there ( not yet returned to the system - for example: data in the static area, heap area) , you can use the reference to return, if it has been returned to the system ( For example: local variables on the function stack frame ), you must return by value.

5. 3 Passing parameters, compared with the efficiency of passing references

    Here is a test program that tests the two methods of function parameter passing.

#include <time.h>
struct A{ int a[10000]; };
void TestFunc1(A a){
  
}

void TestFunc2(A& a){
  
}

void TestRefAndValue()
{
 A a;
 // 以值作为函数参数
 size_t begin1 = clock();
 for (size_t i = 0; i < 10000; ++i)
 TestFunc1(a);
 size_t end1 = clock();
 // 以引用作为函数参数
 size_t begin2 = clock();
 for (size_t i = 0; i < 10000; ++i)
 TestFunc2(a);
 size_t end2 = clock();
// 分别计算两个函数运行结束后的时间
 cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
 cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}

It can be seen that when passing parameters, the speed of passing references is faster than passing values; when passing return values, passing references is also faster than passing values .

 5.4 Common references

    This involves the issue of data permissions

void f()
{
	// 扩大权限
	const int a = 10;  // 这里a只读
	//int& a1 = a;       // 而引用a, 可以读和写,属于是扩大权限,会报错是不允许的。
	const int& a1 = a; // 设置a1 只读
	
	// 缩小权限
	int b = 20;        // 这里b允许 读于写
	const int& b1 = b;  // 被允许是因为只是缩小权限
}

When a non-const modified reference is initialized, the object must be a variable. If it is a constant, the authority is enlarged.

Common constants are:  

1. A variable modified by const.

 const  int  a = 10;

const  int&  a1 = a;  

2. Temporary variables are characterized by being destroyed after the task is completed, and have a short life cycle. (such as: function return value, expression, implicit conversion, parameter passing)

 const int& k = 3 + 4; // will create a temporary variable to store

 const int& z = 1.111; // The int truncated value is placed in a temporary variable

// int& k = 3 + 4; not allowed

 

5.5 The difference between references and pointers 

  •      In the grammatical concept, a reference is an alias, which has no independent space and shares the same space with its referenced entity. 
  •      In the underlying implementation, there is actually space, because references are implemented in the form of pointers .

Let's look at the disassembly of the following code,

int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}

It can be seen that the reference actually has space in the underlying implementation , because the reference is implemented in the form of a pointer , it cannot be said to be the same, but it can only be said to be exactly the same .

 

 5.6 Differences between references and pointers

  • 1. Reference Conceptually defines the alias of a variable, and the pointer stores the address of a variable.
  • 2. The reference must be initialized when it is defined , and the pointer is not required.
  • 3. After the reference refers to an entity during initialization, it can no longer refer to other entities , and the pointer can point to any entity of the same type at any time.
  • 4. There are no NULL references , but there are NULL pointers.
  • 5. The meaning is different in sizeof : the reference result is the size of the reference type , but the pointer is always the number of bytes occupied by the address space. (4 bytes under 32-bit platform)
  • 6. The self-increment of the reference means that the referenced entity increases by 1 , and the self-increment of the pointer means that the pointer is offset by one type of size.
  • 7. There are multi-level pointers, but no multi-level references.
  • 8. The way to access the entity is different. The pointer needs to be explicitly dereferenced, and the reference compiler handles it by itself.
  • 9. References are relatively safer to use than pointers.


Six, inline functions 

      A function decorated with inline is called an inline function. When compiling, the C++ compiler will expand it at the place where the inline function is called . There is no overhead of creating a stack frame for function calls. Inline functions improve the efficiency of program operation.

      

6.1 Features

  • 1. inline is a method of exchanging space for time. If the compiler treats the function as an inline function, it will replace the function call with the function body during the compilation phase . Defect: it may make the object file larger. Advantage: less Call overhead, improve program operating efficiency.
  • 2. Inline is only a suggestion for the compiler. Different compilers may have different implementation mechanisms for inline. The general suggestion is: make the function smaller (that is, the function is not very long, there is no exact statement, it depends on the internal implementation of the compiler) , non-recursive , and frequently called functions should be inline modified, otherwise the compiler will ignore the inline feature.
  • 3. Inline does not recommend separation of declaration and definition, separation will lead to link errors. Because inline is expanded, it will no longer enter the symbol table during assembly, and function relocation cannot be performed during linking, and the link will not be found, as follows:
// F.h
#include <iostream>
using namespace std;
inline void f(int i);
// F.cpp
#include "F.h"
void f(int i)
{
 cout << i << endl;
}
// main.cpp
#include "F.h"
int main()
{
 f(10);
 return 0;
}
// 链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl 
f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用

How to view the inline function to configure the environment?

The operation is as follows:

Just find a source file, right-click to open the properties, and then:

 Then click apply.

Let's test the following code:

#include<iostream>
using namespace std;

inline void func()
{
	;
}

int main()
{
	func();
	func();
	func();
	return 0;
}

 View disassembly:

It can be seen that the inline function does not call the function call here, but is directly expanded at the function call, without the overhead of building a stack.

【Interview questions】
Pros and cons of macros?
advantage:
1. Enhance code reusability.
2. Improve performance.
shortcoming:
1. It is inconvenient to debug macros. (Because of the replacement in the precompilation stage)
2. It leads to poor code readability, poor maintainability, and easy misuse.
3. There is no type safety check.
What are the technical alternatives to macros in C++ ?
1. Constant definition is replaced by const enum
2. Use inline function instead of short function definition

Seven, the auto keyword (C++11)

 7.1 Thinking

As the program becomes more and more complex, the types used in the program become more and more complex, often reflected in:
1. Types are hard to spell
2. Unclear meaning leads to error-prone
#include <string>
#include <map>
int main()
{
 std::map<std::string, std::string> m{ { "apple", "苹果" }, { "orange", 
"橙子" }, 
   {"pear","梨"} };
 std::map<std::string, std::string>::iterator it = m.begin();
 while (it != m.end())
 {
 //....
 }
 return 0;
}

Among them, std::map<std::string, std::string>::iterator is a type. Does it feel cumbersome when writing the type by yourself? At this time, we will think of using typedef to simplify the code, the code is as follows:

typedef char* pstring;
int main()
{
 const pstring p1;    // 编译成功还是失败?
 const pstring* p2;   // 编译成功还是失败?
 return 0;
}

 One thing we need to know is that when we use the renamed type, we must also be clear about the renamed type. In large projects, it is not so easy to remember the renamed type.

Today, auto is given a new definition in the C++11 standard.

 7.2 Introduction to auto

       In C++11, the standard committee gave auto a brand-new meaning: auto is no longer a storage type indicator, but a new type indicator to instruct the compiler, and the variables declared by auto must be compiled by the compiler derived from time period .
Here is a simple usage:
#include<iostream>
using namespace std;
int func()
{
	return 10;
}
int main()
{
	auto a = 10;
	auto b = 'a';
	auto c = 1.2;
	auto d = &a;
	auto e = func();
	//auto z;  使用auto定义变量时必须对其进行初始化.
	return 0;
}

 

(Note: When using auto to define a variable, it must be initialized. At the compilation stage, the compiler needs to deduce the actual type of auto according to the initialization expression. Therefore, auto is not a "type" declaration, but a type declaration. The "placeholder", the compiler will replace auto with the actual type of the variable at compile time .)

7. 3 Auto usage rules

1. Auto is used in combination with pointers and references. When using auto to declare a pointer type, there is no difference between using auto and auto*, but when using auto to declare a reference type, you must add & .

2. Define multiple variables on the same line When declaring multiple variables on the same line, these variables must be of the same type, otherwise the compiler will report an error, because the compiler actually only deduces the first type, and then uses the deduction The type that comes out defines other variables .
void TestAuto()
{
    auto a = 1, b = 2; 
    auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

7.4 Scenarios where auto cannot be derived

 1. auto cannot overturn function parameters

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

 2. auto cannot overturn the array

void TestAuto()
{
   int a[] = {1,2,3};
   auto b[] = {4,5,6};
}
3. In order to avoid confusion with auto in C++98, C++11 only retains the usage of auto as a type indicator.
4. The most common advantage of auto in practice is to use it in conjunction with the new for loop provided by C++11 and lambda expressions that will be mentioned later.

 Eight, range-based for loop (C++)

8.1 Ranged for loop syntax 

    For a bounded collection , it is redundant and sometimes error-prone for the programmer to specify the scope of the loop. Therefore, range-based for loops were introduced in C++11. The parentheses after the for loop are divided into two parts by the colon ":": the first part is the variable used for iteration in the range, and the second part represents the range to be iterated .

 Simple use is as follows:

void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)  
     e *= 2;
for(auto e : array)
     cout << e << " ";
return 0;
}

 analyse as below:

8. 2   Conditions of use of range for

1. The range of for loop iterations must be definite.
void TestFor(int array[])
{
    for(auto& e : array)
        cout<< e <<endl;
}

2. The iterated object must implement ++ and == operations . (Let’s understand this first)

Nine,  pointer null value nullptr (C++11)

9.1 Pointer null in C++98

    In good C/C++ programming practice, it is best to give the variable an appropriate initial value when declaring a variable, otherwise unexpected errors may occur, such as uninitialized pointers. If a pointer does not have a legal point to, we basically initialize it as follows:

     int*  a  =  NULL;

     int*  b  = 0;

  NULL is actually a macro. In the traditional C header file (stddef.h), you can see the following code:
#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif
As you can see, NULL may be defined as the literal constant 0, or as a constant of an untyped pointer (void*) . no matter what
This kind of definition, in C++ programs, when using pointers of null values, it is inevitable to encounter some troubles, such as:
  
#include<iostream>
using namespace std;
int func(int *a)
{
	return 10;
}
int func(int a)
{
	return a;
}
int main()
{
	cout << func(0);  // 我想传NULL指针的0就不合适
	return 0;
}

So NULL in C language is not suitable for use in C++, so nullptr is here !

(Note: In C++98, the literal constant 0 can be either an integer number or an untyped pointer (void*) constant, but the compiler treats it as an integer constant by default. If you want To use it as a pointer, it must be cast to (void*)0.)

Notice:
1. When using nullptr to represent the null value of the pointer, there is no need to include the header file, because nullptr is introduced as a new keyword in C++11 .
2. In C++11, sizeof(nullptr) and sizeof((void*)0) occupy the same number of bytes.
3. In order to improve the robustness of the code, it is recommended to use nullptr when representing the null value of the pointer.

epilogue

This section is over here, thank you friends for browsing, if you have any suggestions, welcome to comment in the comment area, if you bring some gains to your friends, please leave your likes, your likes and concerns will become bloggers The driving force of the master's creation.

Guess you like

Origin blog.csdn.net/qq_72112924/article/details/130454525