💡 本文档记录了笔者2022年暑假啃《Introduction to Programming with C++》这本书自学C++基础的笔记

Contents of this book (Chapter 1-16)#


Chapter 2#

const#

const double PI = 3.14159 // PI值不变,常量命名为全大写

limits#

#include<limits>

内有各种变量类型的上限、下限

e.g INT_MAX = 2147483647

time(0)#

需要 #include<ctime>

显示当前时间距离1970.1.1 00:00:00 有多少秒

显示当前时间

static_cast#

Chapter 3#

bool#

rand and srand#


Chapter 4#

Mathematical Functions#

Character Functions#

string#

string 基础#

string 拼接#

比较大小:按ASCII码依次比较#

string读入#

cout 进阶#

**#include <iomanip>**

setprecision(n)#

The setprecision manipulator remains in effect until the precistion is changed!

fixed#

showpoint#

setw(width)#

left and right#

simple file input and output#

write file#

read file#


Chapter 6#

overloading functions#

function prototype#

default arguments#

constant reference parameters#


Chapter 7#

Passing arrays to functions#

Preventing changes of array arguments in functions#

return an array#


Chapter 8#

Passing two-dimensional arrays to functions#


Object and Class#

Defining Classes and Creating Objects#

code#

When you define a custom class, capitalize the first letter of each word in a class name.

UML notation#

51b1c8c3506c242ff56c56415b8b7c40

Constructors#

Peculiarities#

  • Constructors must have the same name as the calss itself.
  • Constructors do not have a return type–not even void!
  • Constructors are invoked when an object is created. Constructors play the role of initializing objects.

(A data field cannot be initialized when it is declared! like double radius = 5;)

  • If we do not define a constructor, a no-arg constructor with an empty body is implicitly defined in the class. (Default constructor)

Constructor initializer list#

Data fields may be initialized in the constructor using an initializer list in the following syntax:

Using an initializer list is necessary to initialize object data fields that don’t have a no-arg constructor.

Construction and Using Objects#

basics#

object size#

Data are physically stored in an object, but functions are not. Since functions are shared by all objects of the same class, the compiler creates just one copy for sharing.

Separating Class Definition from implementation#

Class Definition: list all the data fields, constructor prototypes, and function prototypes.
Class implementation implements the constructors and functions.
These are in two files, but both files should have the same name but different extension names(.h for data fields and .cpp for implementations).

Inline Functions in Classes#

short functions are good candidates for inline functions.

Data Field Encapsulation#

Making data fields private protects data and makes the class easy to maintain.

  • Data may be tampered with.
  • Public data may makes the class difficult to maintain and vulnerable to bugs.

51b1c8c3506c242ff56c56415b8b7c40

Object-Oriented Thinking#

Passing Objects to Functions#

Passing by reference is preferred, because it takes time and additional memory space to pass by value.

Array of Objects#

Instance and Static Members#

  • A static variable is shared by all objects of the class
  • A static function cannot access instance members of the class

UML graph#

db4c511b00afb99b51a402a46b2a2cf5

Using of static members/functions#

  • If a variable or a function is not dependent on a specific instance of the class, it should be a static variable or static function
  • Using ClassName::functionName(args) to invoke a static function and ClassName::staticVariable to access static variables improves readability.

Constant Member Functions#

A const function should not change the value of any data fields in the object.

Object Composition#

An object can contain another object. The relationship between the two is called composition.

Aggregation and composition#

The owner object is called an aggregating object and its class an aggregating class. The subject object is called an agggregated object and its class an aggregated class.
An object may be owned by several other aggregating objects. If an object is exclusively owned by an aggregating object, the relationship between the object and its aggregation object is referred to as composition.

UML graph#

cefccd87448f7268d2fecb48285860b5

  • Filled diamond is attached to an aggregating class to denote the composition relationship.
  • An empty diamond is attached to an aggregating class to denote the aggregation relationship.

**Aggregation may exist between objects of the same class. **

fc994c0908b088e6ef3f5ddcacd2e355

Thinking in Objects#

  • The procedural paradigm focuses on designing functions. The object oriented paradigm couples data and functions together into objects.
  • Software design using the object-oriented paradigm focuses on objects and operations on objects.

Class Design Guidelines#

  • Cohesion
    • A class describe a single entity, all the class operations should logically fit together to support a coherent purpose.
  • Consistency:
    • Follow standard programming style and naming conventions. Choose informative names for classes, data fields, and functions. Placing data declaration after the functions and place constructors before functions.
    • Choose the same names for similar operations using function overloading.
    • Consistently provide a public no-arg constructor.
  • Encapsulation
    • Using private modifier to hide data.
  • Clarity
    • A class should have a clear contract that is easy to explain and understand.
  • Completeness
    • A class should provide a variety of ways for customization through properties and functions for wide range of applications.
  • Instance vs. Static

Pointers and Dynamic memory management#

Using const with Pointers#

A constant pointer points to a constant memory location, but the actual value in the memory location can be changed.

Passing Pointer Arguments in a Function Call#

A pointer argument can be passed by value or by reference

Returning a Pointer from Functions#

Useful Array Functions#

Dynamic Persistent Memory Allocation#

A new operator can be used to create persistent memory at runtime for primitive type values, arrays, and objects.

C++ allocates local variables in the stack, but the memory allocated by the new operator is in an area of memory called heap. The heap memory remains available until you explicitly free it or the program terminates.

Allocation#

  • int* p = new int(4);means allocate memory space for an int variable initialized to 4
  • int* p = new int[size];means allocate dynamic array

For creating dynamic objects, you can use

  • ClassName* pObject = new ClassName(); or ClassName* pObject = new ClassName; for no-arg constructor.
  • ClassName* pObject = new ClassName(arguments); for creating an object using the constructor with arguments.

Delete#

**To explicitly free the memory creater by the new operator, use the delete operator for the pointer. Like **delete p;**or **delete [] list;

  • Use the delete keyword only with the pointer that points to the memory created by the new operator.
  • After the memory pointed by a pointer is freed, the value of the pointer becomes undefined. Do not apply the dereference operator * on dangling pointer.
  • Do not reassign a pointer before deleting the memory to which it points. It may cause memory leak.

The this Pointer#

The this pointer points to the calling object itself

Destructors#

Every class has a destructor, which is called automatically when an object is deleted.

  • Every class has a default destructor if the destructor is not explicitly defined.
  • Destructors are named the same as class with a destructor defined, but put a tilde character(~) in the front
  • Destructors have no return type and no arguments.

Copy Constructors#

Every class has a copy constructor, which is used to copy objects.

ClassName(const ClassName&)

A default copy constructors is provided for each class implicitly, if it is not defined explicitly. The default copy constructir simply copied each data field in one object to its counterpart in the other object.

Shallow Copy#

The program will display “Si Li” twice and it will cause error before the space for students in course1 is freed (students of course2 have no space!)

Deep Copy#


Inheritance and Polymorphism#

Base Classes and Derived Classes#

**Inheritance enables you to define a general class (i.e., a base class) and later extend it to more specialized classes (i.e., derived classes). **

UML graph#

37602a6369d5075f22d11a6884396062

Syntax#

class derivedClassName : public baseClassName

  • All the public member in bass class are inherited in derived class
  • But the private data fields can not be accessed in the derived class. You can only use get or set functions to read or modify them.
  • A derived class and its base class must have the is-a relationship.
  • Not all “is-a” relationships should be modeled using inheritance. For class A to extend class B, A should contain more detailed information than B.
  • C++ allows you to derive a derived class from several classes. This capability is known as multiple inheritance.

Generic Programming#

An object of a derived class can be passed wherever an object of a base type parameter is required. Thus a function can be used generically for a wide range of object arguments. This is known as generic programming.

Constructors and Destructors#

Calling Base Class Constructors#

Constructor and Destructor Chaining#

**The constructor of a derived class first calls its base class’s constructor before it executes its own code. The destructor of a derived class executes its own code then automatically calls its base class’s destructor. **

**Cautions: **

  • If a class is designed to be extended, it is better to provide a no-arg constructor to avoid programming errors.
  • If the base class has a customized copy constructor and assignment operator, you should customize these in the derived classes to ensure that the data fields in the base class are properly copied.

Redefining Functions#

A function defined in the base class can be redefined in the derived classes.

To redefine a base class’s function in the derived class, you need to add the function’s prototype in the derived class’s header file, and provide a new implementation for the function in the derived class’s implementation file.

Polymorphism#

Polymorphism means that a variable of a supertype can refer to a subtype object.

For example, every circle is a geometric object, but not every geometric object is a circle. Therefore, you can always pass an instance of a derived class to a parameter of its base class type.

Virtual Functions and Dynamic Binding#

A function can be implemented in several classes along the inheritance chain. Virtual functions enable the system to decide which function is invoked at runtime based on the actual type of the object. The capability of determining which function to invoke at runtime is known as dynamic binding.

**To enable dynamic binding for a function, you need to do two things: **

  • The function must be defined virtual in the base class.
  • The variable that references the object must be passed by reference or passed as a pointer in the virtual function

Note

  • Static Binding: The declared type of the variable decides which function to match at compile time. The compiler finds a matching function according to parameter type, number of parameters, and order of the parameters at compile time.
  • Dynamic Binding: Dynamically binds the implementation of the function at runtime, decided by the actual class of the object referenced by the variable.
  • If a function defined in a base class needs to be redefined in its derived classes, you should define it virtual to avoid confusions and mistakes. On the other hand, if a function will not be redefined, it is more efficient not to declare it virtual, because more time and system resource are required to bind virtual functions dynamically at runtime.

The protected keyword#

Keyword Who can access?
public inside the class/ friend functions/ friend classes
protected inside the class/ friend functions/ friend classes/ derived classes
private inside the class/ any other class

Abstract Classes and Pure Virtual Functions#

**An abstract class cannot be used to create objects. An abstract class can contain abstract functions, which are implemented in concrete derived classes. **

For example, getArea function can not be implemented in GeometricObject class, but can be implemented in the Circle class or Rectangle class. So we can define getArea in GeometricObject class as an abstract funcions(Pure Virtual Functions). Then GeometricObject class is a abstract class which cannot be used to create objects.

syntax: virtual type functionName(parameterList) = 0; The “= 0” notation indicates that this function is a pure virtual function. A pure virtual function does not have a body or implementation in the base class.

Casting: static_cast versus dynamic_cast#

The dynamic_cast operator can be used to cast an object to its actual type at runtime.

dynamic_cast can be performed only on the pointer or the reference of a polymorphic type; i.e., the type contains a virtual function. dynamic_cast can be used to check whether casting is performed successfully at runtime. static_cast is performed at compile time.

Example: GeometricObject, Circle, Rectangle#


Templates, Vectors, Stacks#

Templates Basics#

**Templates provide the capability to parameterize types in functions and classes. You can define functions or classes with generic types that can be substituted for concrete types by the compiler **

Cautions:
The generic maxValue function can be used to return a maximum of two values of any type, provided that:

  • The two values have the same type
  • The two values can be compared using the > operator

Occasionally, a template function may have more than one parameter. In this case, place the parameters together inside the brackets, separated by commas, such as template<typename T1, typename T2, typename T3>

Class Templates#

We use a improved stack class as example

048d60a0b39a708cd5f76fbdb2dbdc5f

vector Class#

C++ provides the vector class, which is more flexible than arrays. You can use a vector object just like an array, but a vector’s size can grow automatically if needed.


Operator Overloading#

The Rational Class for this chapter#

**In this chapter, we will overload several operators for using Rational class more conveniently. **
And in this section, we implemented the Rational class without operator overloading first.

Operator functions#

**If we want to compare two Rational objects, we can use the member function compareTo, but overloading <, >, <=, **>=is more conveniently.

**We can overload +, -, *, **/to make calculate Rational objects more conveniently.

image.png

Notes:

  • C++ allows to overload the operators in Table 14.1, but does not allow to create new operators.
  • We cannot change the operator precedence and associativity by overloading
  • Most operator are binary operators. Some are unary. We cannot change the number of operands by overloading.

Overloading the Subscript Operator#

**The subscript operator **[]is commonly defined to access and modify a data field or an element in an object.

In C++, Lvalue (left value) refers to anything that can appear on the left side of the assignment operator (=) and Rvalue (right value) refers to anything that can appear ont the right side of the assignment operator.

If we want to overload a Lvalue operator, we should use return-by-reference.

Overloading Augmented Assignment Operator#

**For augmented assignment operators (+=, -=, *=, **/= and %=) **are Lvalue operators. We can define the augmented assignment operators as functions to return a value by reference. **

Overloading the Unary Operator#

The unary + and operators can be overloaded. Since the unary operator operates on the one operand that is the calling object itself, the unary function operator has no parameters.

Overloading the ++ and – Operator#

The ++ and -- operator may be prefix or postfix, and the methods of overloading prefix ++/-- and postfix ++/-- are different.

Prefix ++/-- is Lvalue operator, so it should return by reference.

Postfix ++/-- are defined with a special dummy parameter of the int type. So when we operator postfix ++/-- the function should have an int type dummy parameter. And Prefix ++/-- operator function do not have parameters.

Overloading the Stream Operator#

friend Functions and friend Classes#

<< and >> must be implemented as friendnonmember functions. So we learn friendfunction and friend class first.

We can define a friend function or a friend class to enable it to access private members in another class.

Overloading << and >>#

The stream extraction (>>) and insertion (<<**) operators can be overloaded for performing input and output operations. **

If we want to display a Rational object r, we will use:

cout << r.toString() << endl;

Wouldn’t it be nice to be able to display r like the following?

cout << r << endl;

But we cannot overload the << operator as a member function for two operands cout is an instance of ostream class, not Rational class.

Similarly, we can overload >> like the following

Automatic Type Conversions#

You can define functions to perform automatic conversion from an object to a primitive type value and vice versa.

C++ can perform certain type conversion automatically. For example, in 4 + 5.5, C++ convert 4 to 4.0 first.

If we want to convert a Rational object to a double value. Here is the implementation.

And if we want to convert a int variable to Rational number. We may use the following code.

A class can define the conversion function to convert an object to a primitive type value or define a conversion constructor to convert a primitive type value to an object, but not both simultaneously in the class. If both are defined, the compiler will report an ambiguity error.

Nonmember Functions for Overloading Operators#

**If an operator can be overloaded as a nonmember function, define it as a nonmember function to enable implicit type conversions. **

In previous sections, we implemented r1 + 4, but we cannot calculate 4 + r1, because the left operand is the calling object for the + operator and the left operand must be a Rational object.
To solve this problem, we may use the following code.

Overloading the = Operators#

You need to overload the = operator to perform a customized copy operation for an object.

The behavior of the operator is the same as the copy constructor, both of these should be implemented explicitly if a data field in the class is a pointe that points to a dynamic generated array or object.

The Rational Class with Overloaded Function Operators#

Note Points for Operator Overloading#

**The preceding sections introduced how to overload function operators. The following points are worth noting: **

  • **Conversion functions: **
    • Conversion funcitons from a class type to a primitive type or from a primitive type to a class type cannot both be defined in the same class. Doing so would cause ambiguity errors, because the compiler cannot decide which conversion to perform. Often converting from a primitive type to a class type is more useful. So, we will define our Rational class to support automatic conversion from a primitive type to the Rational type.
  • **Member or nonmember functions: **
    • Most operators can be overloaded either as member or nonmember functions. However, the =, [], ->, and () operators must be overloaded as member functions and << and >> operators must be overloaded as nonmember functions.
    • If an operator (i.e., +, -, *, /, %, <, <=, ==, !=, >, and >=) can be implemented either as a member or nonmember function, it is better to overload it as a nonmember function to enable automatic type conversion with symmetric operands.
  • Lvalue:
    • If you want the returned object to be used as an Lvalue (i.e., used on the left-hand side of the assignment statement), you need to define the function to return a reference. The augmented assignment operators +=, -=, *=, /=, and %=, the prefix ++ and --operators, the subscript operator [], and the assignment operators = are Lvalue operators.

File Input and Output#

C++ provides the ifstream, ofstream, and fstream classes for processing and manipulating files. These classes are defined in the <fstream> header file.

Text I/O#

Writing Data to File#

The ofstream class can be used to write primitive data-type values, arrays, strings, and objects to a text file.

  • If a file already exists, its contents will be destroyed without warning!
  • The directory separator should be “\” e.g output.open("D:\\example.txt");
  • It is better to use a relative file name rather than absolute file name.

Reading Data from File#

The ifstream class can be used to read data from a text file.

  • To read data correctly, we need to know exactly how data are stored.

Testing File Existence#

If the file does not exist when reading a file, the program will run and produce incorrect results. We can invoke the fail() function immediately after invoking the open function. If fail() returns true, it indicates that the file does not exist.

Testing End of File#

We can invoke the eof() function on the input object to detect the end of file.

  • The statement input >> score is actually invoke an operator function. The function returns an object if a number is read, otherwise it returns NULL

Letting the User Enter a File name#

The file name passed to the input and output stream constructor or the open function must be a C-string in the standard C++. So we must use c_str() function in the string class is invoked to return a C-string from string object.

Formatting Output#

The stream manipulators can be used to format console output as well as file output.
We can include <iomanip> to manipulate output in file.

getline, get and put#

The getline function can be used to read a string that includes whitespace characters and the get/put function can be used to read and write a single character.

Syntax

  • getline(ifstream& input, string s, char delimitChar);

The function stops reading characters when the delimiter character or eof is encountered. The delimitChar has a default value "\n". The getline function is defined in the iostream.

  • get(); or get(char& ch);

The first version returns a character from the input. The second version passes a character reference argument, reads a character from the input, and stores it in ch. This function also returns the reference to the input object being used.

  • put(char ch)

fstream and File Open Modes#

We can use fstream to create a file object for both input and output.

It is convenient to use fstream if a program needs to use the same stream object for both input and output. To open an fstream file, you have to specify a file open mode to tell C++ how the file will be used.

image.png
  • Some of the file modes also can be used with ifstream and ofstream objects to open a file. For example, you may use the ios:app mode to open a file with an ofstream object so that you can append data to the file. However, for consistency and simplicity, **it is better to use the file modes with the **fstream objects.
  • Several modes can be combined using the | operator. This is a bitwise inclusive-OR operator**. For example, to open an output file named city.txt for appending data, we can use the following statement: stream.open("city.txt", ios::out | ios::app);.

Testing Stream States#

The functions eof(), fail(), good(), and bad() can be used to test the states of stream operations.

image.png image.png

Binary I/O#

The ios::binary mode can be used to open a file for binary input and output.
Computers do not differentiate binary files and text files. All files are stored in binary format, and thus all files are essentially binary files. Text I/O is built upon binary I/O to provide a level of abstraction for character encoding and decoding.

The write Function#

syntax:

streamObject.write(const char* s, int size); So we should pass standard C-string into write function.

Often we need to write data other than characters. We can use reinterpret_cast operator to cast any pointer type of unrelated classes. It simply performs a binary copy of the value from one type to the other without altering the data.

syntax: reinterpret_cast<dataType*>(address); And in this case, the dataType is char*

The read Function#

**syntax: **

streamObject.read(char* address, int size);

The size parameter indicates the maximum number of bytes read. The actual number of bytes read can be obtained from a member function gcount.

We can also use reinterpret_cast to cast bytes into types not char

Random Access File#

The functions seekg() and seekp() can be used to move file pointer to any position in a random-access file for input and output.

The seekp("seek put") function is for the output stream, and the seekg("seek get")function is for the input stream. Each function has two versions with one argument or two arguments.

  • With one argument, the argument is the absolut location.

    input.seekg(0);

    output.seekp(0);

  • With two arguments, the first argument is a long integer that indicates an offset, and the second argument, known as the seek base, specifies where to calculate the offset from. The following are three possible seek base arguments.

image.png

Examples:

1660673303647-77023f0d-44bd-43e8-9b55-8d22722e7b60.png

We can also use tellp and tellg functions to return the position of the file pointer in the file.

Updating Files#

We can update a binary file by opening a file using the mode ios::in | ios:out | ios::binary.
Often we need to update the contents of the file. You can open a file for both input and output.

For example: binaryio.open("data.dat"), ios::in | ios::out | ios::binary);


Exception Handling#

Overview#

An exception is thrown using a throw statement and caught in a try-catch block.

The try block contains the code that is executed in normal circumstances. The catch block contains the code that is executed when n2 is zero. When n2 is zero, the program throws an exception by executing throw n1. However, after the catch block has been executed, the program control does not return to the throw statement; instead, it executes the next statement after the catch block.

If you are not interested in the contents of an exception object, the catch block parameter may be omitted.

Advantages of Excpetion-Handling#

Exception handling enables the caller of the function to process the exception thrown from a function.

Without this capability, a function must handle the exception or terminate the program. Often, the called function does not know what to do in case of error. This is typically the case for the library function. The library function can detect the error, but only the caller knows what needs to be done when an error occurs. The fundamental idea of exception handling is to separate error detection (done in a called function) from error handling (done in the calling function).

Exception Classes#

You can use C++ standard exception classes to create exception objects and throw exceptions.
The catch block parameter in the preceding examples is the int type. A class type is often more useful.

1660399673414-5c81c522-d853-476f-b88e-74cb9cb9fdab.jpeg

The root class in this hierarchy is exception(defined in header <exception>). It contains the virtual function what() that returns an exception object’s error message.

The runtime_error class (defined in header <exception>) is a base class for several standard exception classes that describes runtime errors.

The logic_error class (defined in header <stdexcept> ) is a base class for several standard exception classes that describes logic errors.

Custom Exception Classes#

You can define custom exception classes to model exceptions that cannot be adequately represented using C++ standard exception classes.
If we run into a problem that cannot be adequately described by the standard exception classes, we can create our own exception class. This class is just like any C++ class, but often it is desirable to derive it from exception or a derived class of exception so we can use the what() funtion.
The following is an example defining exception class TriangleException for the Triangle class.

A custom exception class is just like a regular class. Extending from a base class is not necessary, but it is a good practice to extend from the standard exception or a derived class of exception so your custom exception class can use the functions from the standard classes.

Multiple Catches#

A try-catch block may contain multiple catch clauses to deal with different exceptions thrown in the try clause.
One catch block can catch only one type of exception. C++ allows we to add mutiple catch block after a try block in order to catch multiple types of exceptions.
Note

  • Various exception classes can be derived from a common base class. If a catch block catches exception objects of a base class, it can catch all the exception objects of the derived classes of that base class.
  • The order in which exceptions are specified in catch blocks is important. A catch block for a base class type should appear after a catch block for a derived class type. Otherwise, the exception of a derived class is always caught by the catch block for the base class!

You may use an ellipsis (...) as the parameter of catch, which will catch any exception no matter what the type of the exception that was thrown. This can be used as a default handler that catches all exceptions not caught by other handlers if it is specified last.

Exception Propagation#

An exception is thrown through a chain of calling functions until it is caught or it reaches to the main function.

  • If no exceptions arise during the execution of the try block, the catch block are skipped.
  • If one of the statements inside the try block throws an exception, C++ skips the remaining statements in the try block and starts the process of finding the code to handle the exception.
    • Each catch block is examined in trun, from first to last, to see whether the type of the exception object is an instance of the exception class in the catch block.
    • If one catch block is matched, the code in the catch block is executed.
    • If no handle is found, C++ exits this function, passes the exception to the function that invoked the function, and continues the same process to find a handler.
    • If no handler is found in the chain of functions being invoked, the program prints an error message on the console and terminates.
1660485527531-320f7dd1-fcbf-4fb8-bdea-c42e2941b9b5.png
  • If the exception type is Exception3, it is caught by the catch block for handling exception ex3 in function2. statement5 is skipped, and statement6 is executed.
  • If the exception type is Exception2, function2 is aborted, the control is returned to function1, and the exception is caught by the catch block for handling exception ex2 in function1. statement3 is skipped, and statement4 is executed.
  • If the exception type is Exception1, function1 is aborted, the control is returned to the main function, and the exception is caught by the catch block for handling exception ex1 in the main function. statement1 is skipped, and statement2 is executed.
  • If the exception is not caught in function2, function1, and main, the program terminates. statement1 and statement2 are not executed.

Rethrowing Exceptions#

After an exception is caught, it can be rethrown to the caller of the function.

The statement throw rethrows the exception so that other handlers get a chance to process it.

Exception Specification#

You can declare potential exceptions a function may throw in the function header.
An exception specification, also known as throw list, lists exceptions that a function can throw. So far, we have seen the function defined without a throw list. In this case, the function can throw any exception. So, it is tempting to omit exception specification. However, this is not a good practice.

A function should give warning of any exceptions it might throw. So that programmers can write robust program to deal with these potential exceptions in a try-catch block.

  • If a function attempts to throw an exception. A standard C++ function unexpected is invoked, which normally terminates the program.
  • If a function specifies bad_exception in its throw list, the function will throw a bad_exception if an unspecified exception is throw from the function.

When to use Exceptions#

Use exceptions for exceptional circumstances, not for simple logic errors that can be caught easily using an if statement.
Exception handling separates error-handling code from normal programming tasks, thus making programs easier to read and to modify. Be aware, however, that exception handling usually requires more time and resources, because it requires instantiating a new exception object, rolling back the call stack, and propagating the exception through the chain of functions invoked to search for the handler.

Use exception handling ✔️ Do not using exception handling ❌
We want the exception to be processed by its caller We can handle the exception in the function where it occurs
Common exceptions that may occur in multiple classes Simple errors that may occur in individual functions
Dealing with unexpected error conditions Dealing with simple, expected situations

A general paradigm for exception handling is that yo

u declare to throw an exception in a function as shown in (a) below, and use the function in a try-catch block as shown in (b).

1660490538058-0aac7662-cef1-4bdc-b653-21c4e2dff87f.png

--------------------The End------------------

本文采用CC-BY-SA-3.0协议,转载请注明出处
作者: 核子