<C++> getting started

On the basis of learning C language, continue to learn C++.

C++ is based on C, accommodates the idea of ​​object-oriented programming , and adds many useful libraries and programming paradigms. After being familiar with the C language, it is helpful to learn C++.

1. Supplement the lack of C language grammar, and how C++ optimizes the unreasonable design of C language, such as: scope, IO, function, pointer, macro, etc.
2. Lay the foundation for subsequent class and object learning.

C++ compatible C language syntax

C++ is backward compatible with the C language, which means that almost all legal C code can also be compiled and run in C++. C++ was originally designed as a superset of C, so C++ retains most of the features and syntax of the C language, while introducing some new features.

Example :

#include <iostream>
using namespace std;
int main(){
    
    
    cout << "hello world" << endl;  //hello world
    printf("hello world\n");  //hello world
    return 0;
}

But not 100% compatible. This means that, a lot of legal C code is also valid in C++, and can be compiled and run in C++, but there are also some cases where there are differences between C and C++, and some modifications may be required to work correctly.

1. C++ keywords

// C++ 关键字列表
 
// 基本类型关键字
bool    char    int    float    double    void
short   long    signed  unsigned
 
// 控制流关键字
if      else    switch  case      default
while   do      for     break     continue
return  goto
 
// 函数相关关键字
typedef  constexpr  static_cast  dynamic_cast  reinterpret_cast
const_cast  sizeof    typeid    noexcept      operator
new        delete    this       virtual       override
final      template  typename   using         try
catch
 
// 类、对象和访问控制关键字
class    struct    union    enum    private    protected
public   friend   virtual  explicit mutable    constexpr
 
// 命名空间关键字
namespace  using
 
// 异常处理关键字
throw     try      catch
 
// 杂项关键字
asm     auto     register   volatile
 
// C++11及以后新增关键字
nullptr  enum class  static_assert  alignas    alignof
decltype  noexcept    constexpr     thread_local
 
// C++11以后引入的一些预处理器命令
static_assert  alignof  alignas  __has_include  __has_cpp_attribute
 
// C++17及以后新增关键字
inline  if constexpr  namespace
 
// C++20及以后新增关键字
concept  requires
 
// C++20引入的模块化关键字
import  module  export
 
// C++23中引入的预处理器关键字
__VA_OPT__

2. Namespace

A namespace in C++ is a mechanism for organizing code that encapsulates identifiers in the global scope (such as variables, functions, classes, etc.) in a logical group, thereby preventing name conflicts and providing better code organization structure.

Why Design Namespaces?

Namespaces are designed to resolve code organization and name conflict issues. In a large software project, there may be thousands of functions, variables, classes, etc. Without namespaces, all these identifiers would be in the global scope, easily leading to name collisions and confusing code structures.

Example:

#include <stdio.h>
#include <stdlib.h>
int rand = 10; 

// C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
int main(){
    
    
    printf("%d\n", rand);

    return 0;
}
// 编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”

The rand variable of the above code is the function name in the C language stdlib and cannot be defined. C language can't solve naming conflicts like this, so C++ proposes namespaces to solve

insert image description here

2.1 Scope specifier::

domains: global domain and local domain

int a = 2;

void f1(){
    
    
    int a = 0;
    printf("%d\n", a);   //0
    printf("%d\n",::a);  // 2 ::域作用限定符,表示全局域
}

int main(){
    
    
    printf("%d\n", a);  //2
    f1();

    return 0;
}

Scope specifiers ::can also be used to access members within scopes such as namespaces, classes, structures, enumerations, and global variables.

2.2 Definition of Namespace

namespace MyNamespace {
    
    
    // 声明或定义一些变量、函数、类等
}

Example:

// phw是命名空间的名字,一般开发中是用项目名字做命名空间名。
//1. 正常的命名空间定义
namespace phw{
    
    
    // 命名空间中可以定义变量/函数/类型
    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;
    }
}

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

2.3 Use of Namespaces

#include<iostream>
namespace phw {
    
    
    // 命名空间中可以定义变量/函数/类型
    int a = 0;
    int b = 1;
    int Add(int left, int right) {
    
    
        return left + right;
    }
    struct Node {
    
    
        struct Node *next;
        int val;
    };
}// namespace phw

int main() {
    
    
    printf("%d\n", a);
    return 0;
}

Compile error: error C2065: "a": undeclared identifier, no namespace introduced

There are three ways to use namespaces:

  1. Add namespace name and scope qualifier

    int main(){
          
          
        printf("%d\n", phw::a);
        return 0;    
    }
    
  2. Use using to introduce a member in the namespace

    using phw::b;
    int main(){
          
          
        printf("%d\n", phw::a);
        printf("%d\n", b);
        return 0;    
    }
    
  3. Use the using namespace namespace name to import

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

Using namespace global expansion, in general, global expansion is not recommended.

For the project factory actually developed, we can expand the commonly used parts. For small programs and daily exercises, it is less likely to find conflicts, so you can use global expansion.

For example:

#include <iostream>
//using namespace std;
//常用展开
using std::cout;
using std::endl;


int main() {
    
    
    cout << "1111" << endl;
    cout << "1111" << endl;
    cout << "1111" << endl;
    cout << "1111" << endl;

    int i = 0;
    std::cin >> i;

    return 0;
}

3. C++ input & output

In C++, input and output are done through the input and output stream (iostream) provided by the standard library. There are two main stream objects defined in the standard library: cinfor input (console input) and coutfor output (console output). These correspond to standard input and standard output, respectively.

Example:

#include <iostream>

int main() {
    
    
    int number;
    std::cout << "Enter a number: ";
    std::cin >> number;
    std::cout << "You entered: " << number << std::endl;
    return 0;
}

In the above example, std::cin >> number;the statement reads the data entered by the user into numbera variable.

insert image description here

Both cout and cin can automatically identify variable types

For example:

#include <iostream>
using namespace std;

int main() {
    
    
    char name[10] = "张三";
    int age = 18;
    //...

    cout << "姓名:" << name << endl;
    cout << "年龄:" << age << endl;

    printf("姓名:%s\n年龄:%d\n", name, age);

    return 0;
}

Output result:

姓名:张三
年龄:18
姓名:张三
年龄:18

The difference between endl and "\n":

std::endlis a special operator that inserts a newline and flushes the output buffer. "\n"is an escape sequence for newline, but it doesn't flush the output buffer.

#include <iostream>

int main() {
    
    
    std::cout << "Hello" << std::endl; // 输出 "Hello" 并换行
    std::cout << "World\n"; // 输出 "World" 并换行(但不刷新输出缓冲区)
    return 0;
}

In addition to cinand cout, the standard library also provides other input and output streams, such as cerr(for outputting error messages) and clog(for outputting log information when the program is running). Their usage is similar to cinand coutwith some minor differences.

#include <iostream>

int main() {
    
    
    std::cerr << "This is an error message." << std::endl;
    std::clog << "This is a log message." << std::endl;
    return 0;
}

Notice:

There are many more complex usages of cout and cin, such as controlling the output precision of floating-point numbers, controlling the binary format of integer output, and so on. However, C++ is compatible with C language syntax, it is troublesome to control the output precision of floating-point numbers, and control the format of plastic output. It is troublesome to use cout. It is recommended to use the printf function and scanf function of C language.

4. Default parameters

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.

Example:

#include <iostream>
using namespace std;

//形参a是一个缺省值
void Func(int a = 0) {
    
    
    cout << a << endl;
}

int main() {
    
    
    Func(1);   
    Func();    

    return 0;
}

insert image description here

When the Func function does not pass a parameter, the default value of the parameter is 0, and when the parameter is passed, the specified actual parameter is used

4.1 Classification of default parameters

Divided into full default and semi default

  • All default parameters

Example:

#include <iostream>
using namespace std;

//全缺省
void Func(int a = 10, int b = 20, int c = 30)
{
    
    
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	cout << endl;
}

int main()
{
    
    
	// 使用缺省值,必须从右往左连续使用
	Func(1, 2, 3);
	Func(1, 2);
	Func(1);
	Func();

	return 0;
}

insert image description here

  • semi-default parameter

Example 1:

#include <iostream>
using namespace std;

// 半缺省
// 必须从右往左连续缺省
void Func(int a, int b = 10, int c = 20)
{
    
    
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	cout << endl;
}

int main()
{
    
    
	// 使用缺省值,必须从右往左连续使用
	Func(1, 2, 3);
	Func(1, 2);
	Func(1);

	return 0;
}

insert image description here

Example 2:

#include <iostream>
using namespace std;

struct Stack {
    
    
    int *a;
    int top;
    int capacity;
};
//defaultCapacity缺省参数
void StackInit(struct Stack *ps, int defaultCapacity = 4) {
    
    
    ps->a = (int *) malloc(sizeof(int) * defaultCapacity);
    if (ps->a == NULL) {
    
    
        perror("malloc fail");
        exit(-1);
    }
    ps->top = 0;
    ps->capacity = defaultCapacity;
}


int main() {
    
    
    Stack st1;// 最多要存100个数
    StackInit(&st1, 100);

    Stack st2;// 不知道多少数据,不传size,默认就是缺省参数的值4
    StackInit(&st2);
    return 0;
}

Notice:

  1. The semi-default parameters must be given sequentially from right to left, and cannot be given alternately.

  2. Default parameters cannot appear in both function declaration and definition

For example:

insert image description here

  1. The default value must be a constant or a global variable

5. 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.

Conditions for function overloading :

In order to successfully overload a function, the function overload must satisfy the following conditions:

  1. The function names are the same.
  2. functions are in the same scope.
  3. The parameter lists differ, including the type, number or order of the parameters.

Example 1 :

#include <iostream>
using namespace std;
// 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;
}

void f() {
    
    
    cout << "f()" << endl;
}

void f(int a) {
    
    
    cout << "f(int a)" << endl;
}

// 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;
}

int main() {
    
    
    Add(10, 20);    //int Add(int left, int right)
    Add(10.1, 20.2);//double Add(double left, double right)
    f();            //f()
    f(10);          //f(int a)
    f(10, 'a');     //f(int a,char b)
    f('a', 10);     //f(char b, int a)

    return 0;
}

5.1 C++ supports the principle of function overloading name mangling

The principle of C++ supporting function overloading is based on the compiler's name manglingtechnology, which is a method of combining the function name and its parameter type to generate a unique identifier, which is used to distinguish different functions with the same name. For example, if there are two functions called func, but one argument is an int and the other is a double, the compiler will change their names to something like _Z4funcci and _Z4funcd so that they can be linked correctly Find the corresponding function. Different compilers may have different name manglingrules, but the principle is the same.

From the following, we can see that the name of the gcc function remains unchanged after modification. And the modified function of g++ becomes [_Z+function length+function name+type initials].

The result of using the gcc compiler:

insert image description here

The result of compiling with g++:

insert image description here

6. Inline functions

The modified inlinefunction 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 for function calling to build a stack frame. Inline functions improve the efficiency of program operation.

insert image description here

If you add a keyword before the above function inlineto change it into an inline function, the compiler will replace the function call with the function body during compilation.

View by:

1. In release mode, check whether call Add exists in the assembly code generated by the compiler

insert image description here

2. In debug mode, the compiler needs to be set, otherwise it will not expand (because in debug mode, the compiler will not optimize the code by default, the setting method of vs2022 is given below)

insert image description here

insert image description here

6.1 Characteristics of Inline Functions

  • inlineIt 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 target file larger. Advantage: less call overhead, Improve program operation efficiency .

  • inlineIt is just a suggestion for the compiler . Different compilers may have different inline implementation mechanisms . 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), not recursion , and frequently called functions should be inline modified , otherwise the compiler will ignore the inline feature.

  • inlineSeparation of declaration and definition is not recommended, separation will lead to linking errors. Because inline is expanded, there is no function address, and the link will not be found

  • Definitions of inline functions are usually placed in header files. This is because the compiler needs to be able to expand the function's code inline at the call site when the function is called, and the function definition must be visible to the compiler. If the function definition is placed in the source file, it will not be expanded inline when called by other files.

insert image description here

6.2 Disadvantages of C language 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++?

  • constand enum alternative macro constants
  • inlineto replace the macro function

Use macros:

#define ADD(x, y) x + y;
#define ADD(x, y) (x + y)
#define ADD(x, y) (x) + (y)
#define ADD(x, y) ((x) + (y));

#define ADD(x, y) ((x) + (y))
#define ADD(x, y) (x + y)
#define ADD(x, y) (x) + (y)
#define ADD(x, y) x + y


int main() {
    
    
    ADD(1, 2) * 3;// ((1)+(2))*3;

    int a = 1, b = 2;
    ADD(a | b, a & b);// ((a | b) + (a & b));;

    return 0;
}

Use inline instead

inline int Add(int x, int y) {
    
    
    int z = x + y;
    z = x + y;
    z += x + y;
    //z = x + y;
    //z = x + y;
    //z = x * y;
    //z = x + y;
    //z += x + y;
    //z -= x + y;
    //z += x + y;
    //z += x * y;
    //z -= x / y;
    //z += x + y;
    //z += x + y;

    return z;
}

int main() {
    
    
    int ret = Add(1, 2);
    cout << ret << endl;

    return 0;
}

Guess you like

Origin blog.csdn.net/ikun66666/article/details/132019634