[basic], [v], [supplement] c + + learning diary

C + + learning diary

Double colon scope operator

:: scope operator, when there is no scope before::, it means to use global scope

#include<iostream>
using namespace std;
int a = 1000;
int main()
{
	int a = 2000;
	cout << "Local variable:" << a << endl;
	cout << "Global variable:" << ::a << endl;
	return 0;
}

Namespace namespace

1. Resolve naming conflicts
2. Can store variables, functions, structs, classes
3. Namespace must be declared under global scope
4. Namespaces can be nested
5. Namespace is open. You can add new members to the namespace at any time, define the existing namespace, and merge
6. Namespace can be anonymous, which is equivalent to adding the keyword static before it
7. Namespace can be aliased

#include<iostream>
using namespace std;

// 2. Store variables, functions, etc
namespace A
{
	int m;
	void find(){}
	struct MyStruct
	{
		int  n;
	};
}

// 4. Namespaces can be nested
namespace B
{
	int m;
	namespace C
	{
		int n;
	}
}

// 5. Namespace is open, you can add new members to the namespace at any time
namespace B
{
	int c;
}

// 6. Namespace can be anonymous, which is equivalent to adding the keyword static before it
namespace
{
	int a = 100;
	int b = 200;
}

// 7. Namespace can be aliased
namespace longname
{
	int a;
}

void test01()
{
	B::C::n = 10;
	cout << B::C::n << endl;
}
void test02()
{
	B::c = 10;
	cout << B::c << endl;
}
void test03()
{
	namespace shortname = longname;
	shortname::a = 10;
	cout << shortname::a << endl;
}
int main()
{
	// 4. Namespaces can be nested
	test01();
	// 5. Namespace is open, you can add new members to the namespace at any time
	test02();
	// 7. Namespace can be aliased
	test03();
	return 0;
}

Using declaration and using compilation instructions

#include<iostream>
using namespace std;

namespace A
{
	int m = 10;
}


void test01()
{
	// using declaration
	using A::m;
	// If the principle of proximity appears, ambiguity should be avoided
	//int m = 20;
	//Cout < m < endl; / / error
	//Cout < A:: m < endl; / / error
}
void test02()
{
	// using compilation instructions
	using namespace A;
	// In case of the principle of proximity, priority shall be given to the principle of proximity (partial)
	// If there are elements with the same name in more than one namespace, you need to indicate the scope
	int m = 20;
	cout << m << endl;
	cout << A::m << endl;
}

int main()
{
	// using declaration
	test01();
	// using compilation instructions
	test02();
	return 0;
}

The enhancement of c + + to c

1. Global variable detection enhancement
For example, the following code can be passed in C, but not in C + +

int a;
int a = 10;

2. Function detection enhancements. Parameter variable type detection enhancement, function declaration return value detection enhancement, function return value detection enhancement, call parameter number detection enhancement

3. Type conversion detection enhancements
For example, the following code passes in C, not in C + +, and malloc returns void*

char *p = malloc(64);

Casts are required in C + +

char *p = (char *)malloc(64);

4. For struct enhancement, functions cannot be placed in the structure in C language, but in C + +; struct must be added in the declaration structure in C language, but not in C + +

5. Bool type is enhanced. There is no bool type in C language, but there is

6. Trinocular operator enhancement
Value is returned in C language, and variable is returned in C + +
For example, the following code cannot be run in C language, and can be used in C + +

int a = 10;
int b = 20;
a > b ? a : b = 100

7. const enhancements
In C language, the local const modifier variable can be modified (pointer) indirectly, but not globally. It cannot be used to initialize an array
In C + + language, the local const modifier variable can not be modified indirectly (pointer), nor can it be global. It can be used to initialize an array
When C + + uses pointer to modify local const variables, it is equivalent to having a temporary variable to store const variables, and the pointer is equal to the address of the temporary variable, not directly modified to const constant
const is an external (external document can be used) link attribute by default in C language. By default, extern is added before the global variable
In C + +, the default is internal (only this file) link attribute, which must be added manually
extern to improve scope

Memory allocation of const

1. When the address of the const decorated variable is taken, memory will be temporarily allocated

const int A = 10;
int *p = (int *)&A;

2. After adding the extern keyword before const, memory will also be allocated
3. Use variables to initialize const decorated variables

int a;
const int A = a;
int *p = (int *)&A;
*p = 20;
// A becomes 20
cout << A << endl;

4. For custom data types, memory is also allocated

struct Person
{
	string name;
	int age;
};
int main()
{
	const Person p;
	// It can not be modified directly, but can be modified indirectly
	Person *pp = (Person *)&p;
	pp->name = "Zhang San";
	pp->age = 18;
	cout << pp->name << endl;
	cout << pp->age << endl;
	return 0;
}

The difference between const and define

1. const has type, which can be used for compiler security check. ාdefine has no type, which cannot be used for type check
2. const has scope, but define does not pay attention to scope. The default definition is at the end of the file. If you define a valid constant under the specified scope, then define cannot be used

Inline function

Macro function defect:
1. To ensure the integrity of the operation, parentheses should be added
2. Parentheses were added in time, and some cases still did not meet the expected results
3. Ignore scope

#define Myadd(x, y) x+y
int main()
{
	int a = 10;
	int b = 20;
	cout << Myadd(a, b) << endl;  // Output 30
	cout << Myadd(a, b) * 100 << endl; // Output 210, expected 300
	return 0;
}

After parenthesis

#define Myadd(x, y) ((x)+(y))
int main()
{
	int a = 10;
	int b = 20;
	cout << Myadd(a, b) << endl;  // Output 30
	cout << Myadd(a, b) * 100 << endl; // Output 300, expected 300
	return 0;
}

Problems that can't be solved with parentheses

#define Mycompare(x, y) (((a) > (b)) ? ((a) : (b)))
int main()
{
	int a = 10;
	int b = 20;
	cout << Mycompare(a, b) << endl;  // Output 20
	//  Myadd(++a, b) ⇒ (((++a) > (b)) ? ((++a) : (b)))
	cout << Myadd(++a, b) << endl; // Output 12, expectation 11
	return 0;
}

inline has all the behaviors of ordinary functions, and will be expanded like predefined macros in appropriate places. Therefore, it does not need the cost of function calls, and can replace macro definitions
be careful:
1. The keyword inline must be added before declaration and definition, otherwise it will not be used as inline function
2. The inline keyword is added before the member function by default
The compiler does not inline a function if:
1. There cannot be any form of circular statement
2. There cannot be too many conditional statements
3. Function body cannot be too large
4. The function cannot be valued

extern

Purpose: C language files can be run in C + +
When using a function of an external file (C file), an unexpected error occurs because the name is decorated when C + + links
The solution is as follows:
1. Tell the compiler to link in C, not in C + +

extern "C" function name ();

2. Set in the external file (C file) with the following code

// Before the document header
#ifdef __cplusplus
extern "C" {
#endif
// Add at the end of the document
#ifdef __cplusplus
}
#endif

For example:

#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
void show();
#ifdef __cplusplus
}
#endif

explicit

Purpose: to prevent implicit type conversion from initializing objects

class MyString
{
public:
	MyString(char *str)
	{
	}
	explicit MyString(int len)
	{
	}
	char *str;
	int len;
}
int main()
{
	MyString s1 = "abc";
	MyString s2 = 10;  // error
	MyString s3(10);
	MyString s4 = MyString (20);
	return 0;
}

Singleton mode

Only one instance can be created

class ChairMan
{
public:
	// Data is shared, and only one object pointer is allowed
	// Return pointer
	static ChairMan* getInstance()
	{
		return this->singleMan;
	}
private:
	// Constructor privatization
	ChairMan(){};
	// Prevent copy construction and privatize copy construction
	ChairMan(const ChairMan &c){};
private:
	// Prevent external modification of pointer, set to private 
	static ChairMan * singleMan;
}
ChairMan* ChairMan::singleMan = new ChairMan;

Up down type conversion

Space size: subclass > = parent

// Down conversion, parent rotor, unsafe
Animal *animal = NULL;
Cat * cat = (Cat *) animal;
// Upcast, child to parent, safe
Cat *cat = NULL;
Animal * animal = (Animal *) cat;

Note: if polymorphism occurs, it is always safe

Type conversion

Static conversion_ cast)

1. Used for conversion of pointer or reference between base class (parent class) and derived class (child class) in class hierarchy
It is safe to perform an uplink conversion (convert the pointer or reference of a derived class to the base class representation), child ----- > parent
When performing a downstream conversion (converting a pointer or reference of a base class to a derived class representation), it is not safe because there is no dynamic type checking. Parent ----- > child
2. Used for conversion between basic data types, such as int and char. The security of this transformation also needs to be guaranteed by the developers

#include<iostream>
using namespace std;
// 1. Static type conversion
void test01()
{
	// Built in data type
	char a = 'a';
	// static_ Cast < target type > (original object)
	double d = static_cast<double>(a);
	cout << d << endl;
}
class Base{};
class Son:public Base{};
class Other{};
void test02()
{
	// Custom data type
	Base *b = NULL;
	Son *s = NULL;
	// Base conversion to Son * type, down conversion is not safe
	Son *s2 = static_cast<Son*>(b);  // success
	// Son to Base * type, up type safe
	Base *b2 = static_cast<Base*>(s);  // success
	// base to other * type
	// Conversion between two types without parent-child relationship is not successful
	Ohter *o = static_cast<Other*>(b);  // Error, unsuccessful
}

Dynamic transformation_ cast)

1,dynamic_cast is mainly used for up conversion and down conversion between class levels
2. When the class level is up converted, dynamic_cast and static_ The effect of cast is the same
3. When performing downlink conversion, dynamic_cast has the function of type checking, which is better than static_ More secure cast
4. Any conversion with problems is not supported. For example, the precision of double to int is missing, and the conversion of built-in data type is not supported

#include<iostream>
using namespace std;
// 2. Dynamic type conversion
class Base{};
class Son:public Base{};
class Other{};

class Animal
{
	virtual void func(){};
};
class cat:public Animal
{
	void func(){};
}
void test02()
{
	// Custom data type
	Base *b = NULL;
	Son *s = NULL;
	// Base conversion to Son * type, down conversion is not safe
	Son *s2 = dynamic_cast<Son*>(b);  // Error, unsuccessful
	// Son to Base * type, up type safe
	Base *b2 = dynamic_cast<Base*>(s);  // success
	// base to other * type
	// Conversion between two types without parent-child relationship is not successful
	Ohter *o = dynamic_cast<Other*>(b);  // Error, unsuccessful

	// If polymorphism occurs, the transition between father and son is always safe
	Animal *a = new Cat;
	// Animal to Cat * type, down type
	Cat *c2 = dynamic_cast<Cat*>(a);  // success
}

Constant conversion (const_cast)

This operator is used to modify const property of type, const from nothing to have, from have to no
1. Constant pointers are converted to non constant pointers and still point to the original object
2. Constant references are converted to non constant references and still point to the original object
Note: const cannot be used directly for non pointer and non reference variables_ Cast operator to remove its const directly

// Constant pointer is converted to non constant pointer
void test01()
{
	const int *p = NULL;
	int *p = const_cast<int*>(p);
	int *pp = NULL;
	const int *npp = const_cast<const int*>(pp);
	const int a = 10;
	int b = const_cast<int>(a);  // Error, cannot convert non pointer or reference
}

reinterpret_cast)

1. The most insecure transformation mechanism, most likely to have problems
2. It is mainly used to convert one data type from one data type to another. It can convert a pointer to an integer or an integer to a pointer

C + + exception

Error handling in C language: 1. Use integer return value to identify the error; 2. Use errno macro (which can be simply understood as a global variable) to record the error
throw exception in C + +, try to catch exception, catch catch exception
Note: the exception thrown by throw must be caught. If the exception is thrown and there is no matching type catch in catch, the terminate function will be run, and its default function is abort to terminate the program
You can also use custom type exceptions

#include<iostream>
using namespace std;
class MyException
{
public:
	void print()
	{
		cout << "My own extraordinary mistake" << endl;
	}
};
int MyDiv(int a, int b)
{
	if (b == 0)
	{
		//throw 1;
		//throw 3.14;
		//throw 'a';
		throw MyException();  // Throw anonymous object
	}
	return a / b;
}
void test01()
{
	int a = 10, b = 0;
	try
	{
		MyDiv(a, b);
	}
	catch (int)
	{
		cout << "test01 Middle throw int Exception of type" << endl;
	}
	catch (double)
	{
		cout << "test01 Middle throw double Exception of type" << endl;
	}
	catch(MyException e)
	{
		e.print();
	}
	catch (...)
	{
		// Do not handle exceptions thrown up
		throw;
		cout << "test01 Other types of exceptions are thrown in" << endl;
	}
}
int main()
{
	try
	{
		test01();
	}
	catch (int)
	{
		cout << "main Middle throw int Exception of type" << endl;
	}
	catch (double)
	{
		cout << "main Middle throw double Exception of type" << endl;
	}
	catch (...)
	{
		cout << "main Other types of exceptions are thrown in" << endl;
	}
	return 0;
}

Stack unwinding

From the start of try code to throw exception, all objects on the stack are released in the reverse order of release and construction

Abnormal interface declaration

1. In order to enhance the readability of the program, you can list all types that may throw exceptions in the function declaration, such as: void func() throw(A,B,C); this function func can and can only throw exceptions of types A,B,C and their subtypes
2. If there is no exception interface declaration in the function declaration, this function can throw any type of exception, for example: void func();
3. A function that does not throw any type of exception can be declared as: void func() throw();
4. If a function runs out of an exception that is not allowed to be thrown by its exception interface declaration, the unexpected function will be called. The default behavior of the function is to call the terminate function to interrupt the program

Life cycle of abnormal variable

class MyException
{
public:
	MyException()
	{
		cout << "MyException Constructor" << endl;
	}
	MyException(const MyException& e)
	{
		cout << "MyException Copy construct call" << endl;
	}
	~MyException()
	{
		cout << "MyException Destructor" << endl;
	}
};
void doWork()
{
	throw MyException();
}
void test01()
{
	try
	{	
		doWork();
	}
	 // MyException e calls the copy constructor
	 // MyException *e, receive with pointer, throw & myexception(); anonymous object, object is released, can no longer operate e
	 // You can also throw a new MyException() to receive it with a pointer, but you need to release it manually
	 // Myexception & E, so receive by reference
	catch (MyException &e)
	{
		cout << "MyException Exception capture for" << endl;
	}
}
int main()
{
	test01();
	return 0;
}

Abnormal polymorphic use

// Exception base class
class BaseException
{
public:
	virtual void printError() = 0;
};
// Null pointer exception class
class NullPointException:public BaseException
{
public:
	virtual void printError()
	{
		cout << "Null pointer exception" << endl;
	}
};
// Cross boundary anomaly
class OutOfRangeException:public BaseException
{
public:
	virtual void printError()
	{
		cout << "Cross boundary anomaly" << endl;
	}
};
void doWork()
{
	throw NullPointException();
}
void test01()
{
	try
	{
		doWork();
	}
	catch(BaseException &e)
	{
		e.printError();
	}
}

System standard exception class


Members of the standard exception class:
1. In the above inheritance system, each class provides constructor, copy constructor and assignment operator overload
2,logic_error class and its subclass, runtime_ The error class and its subclasses, whose constructors accept a formal parameter of string type for the description of exception information
3. All exception classes have a what() method that returns the value of const char * type (C-style string), describing the exception information
Specific description of standard exception class:

Exception name describe
exception Parent of all standard exception classes
bad_alloc When the request to allocate memory fails when operator new and operator new []
bad_exception This is a special exception, if bad is declared in the function's exception throw list_ Exception exception: when an exception is thrown inside a function, an exception that is not in the list will be thrown. This is an unexpected function called. If an exception is thrown, no matter what type, it will be replaced with bad_exception type
bad_typeid Use the typeid operator to operate on a NULL pointer, which is a class with a virtual function, and then throw bad_typeid exception
bad_cast Using dynamic_ When the cast conversion reference fails
ios_base::failure Error in io operation
logic_error Logical errors, errors that can be detected before running
runtime_error Runtime errors, errors that can only be detected at runtime

logic_ Subclass of error:

Exception name describe
length_error When trying to generate an object that exceeds the maximum length of the type, such as the resize operation of vector
domain_error The value range of the parameter is wrong, which is mainly used in mathematical functions. For example, using a negative value to call a function that can only operate on non negative numbers
out_of_range Out of valid range
invaild_argument Parameter is not appropriate. In the standard library, this exception is thrown when bitset is constructed with string object and the character in string is not '0' or '1'

runtime_ Subclass of error:

Exception name describe
range_error The calculation results are beyond the range of meaningful values
overflow_error Arithmetic overflow
underflow_error Arithmetic underflow
invaild_argument Parameter is not appropriate. In the standard library, this exception is thrown when bitset is constructed with string object and the character in string is not '0' or '1'

For example:

#include<iostream>
using namespace std;
#include<stdexcept>
void doWork(int age)
{
	if (age < 0 || age > 150)
	{
		throw out_of_range("Age crossing");
	}
}
void test01()
{
	int a = 151;
	try
	{
		doWork(a);
	}
	catch (exception &e)
	{
		cout << e.what() << endl;
	}
}
int main()
{
	test01();
	return 0;
}

C + + input and output streams

Standard input stream

cin.get()     // Read only one character at a time test01()
cin.get()     // Pass in a parameter
cin.get()     // Passing in two parameters does not take the newline test02()
cin.getline() // Passing in two parameters, taking the newline, but throwing away the newline test03()
cin.ignore()  // There are two kinds of test04() test05() without parameters
cin.peek()    // Peep back to est06()
cin.putback() // Put back test07()
void test01()
{
	// Enter a s \ n, a s in the buffer will wrap, the first will take a, the second will take s, the third will take a new line, and the fourth will wait for the next input
	char c = cin.get();
	cout << "c = " << c << endl;
	c = cin.get();
	cout << "c = " << c << endl;
	c = cin.get();
	cout << "c = " << c << endl;
	c = cin.get();
	cout << "c = " << c << endl;
}
void test02()
{
	char buf[1024];
	cin.get(buf, 1024);
	char c = cin.get();
	if (c = '\n')
	{
		cout << "Line feed still in buffer" << endl;
	}
	else
	{
		cout << "Line feed not in buffer"  << endl;
	}
}
void test03()
{
	char buf[1024];
	cin.getline(buf, 1024);
	char c = cin.get();
	if (c = '\n')
	{
		cout << "Line feed still in buffer" << endl;
	}
	else
	{
		cout << "Line feed not in buffer"  << endl;
	}
}
void test04()
{
	// Enter as\n
	cin.ignore();  // No parameter means one character is ignored
	char c = cin.get();
	// Output s
	cout << "c = " << c << endl;
}
void test05()
{
	// Enter as\n
	cin.ignore(2);  // With parameter n, n characters are ignored
	char c = cin.get();
	// Output \ n
	cout << "c = " << c << endl;
}
void test06()
{
	// Enter as\n
	// Take a peek at a and put it back in the buffer, which is still as\n
	char c = cin.peek();
	// Output a
	cout << "c = " << c << endl;
	c = cin.get();
	// Output a
	cout << "c = " << c << endl;
}
void test07()
{
	// Type hello world\n
	char c = cin.get();
	cin.putback(c);  // Take it up, putback
	char buf[1024];
	cin.getline(buf, 1024);
	// Output hello world\n
	cout << buf << endl;
}

Standard output stream

Character output

cout.flush()    // Refresh buffer, effective under linux
cout.put()      // Write characters to buffer
cout.write()    // Write num bytes from buf to current output stream
void test()
{
	// Output single character a
	cout.put('a');
	// Output character bc
	cout.put('b').put('c');
	char buf[] = "hello world";
	// Output hello world
	cout.write(buf, strlen(buf));
}

Format output

(not summarized yet)

Keywords: C Attribute Linux

Added by ghazianibros on Sun, 21 Jun 2020 06:30:36 +0300