C++11 Primer Plus learning notes written by myself, if there is any similar, please correct any mistakes


1. Classes and dynamic memory allocation

Dynamic memory and classes

  • Instead of allocating storage space for the string itself, the class declaration uses new in the constructor to allocate space for the string, which avoids pre-defining the length of the string in the class declaration.
  • Can’t initialize a static member variable in a class declaration because the declaration describes how memory is allocated, but it doesn’t
  • Initialization is in the method file, not in the class declaration file
  • Static data members are declared in the class declaration and initialized in the file that contains the class methods. The scope operator is used during initialization to indicate the class to which the static member belongs. But if the static member is an integer or enumerated type, it can be initialized in the class declaration

When using one object to initialize another, the compiler automatically generates the following constructors:

StringBad sail = sports;   Sports is a StringBad object
/ / equivalent to the
StringBad sail = StringBad(sports);Copy the code
  • 1
  • 2
  • 3

C++ provides the following member functions:

  • Default constructor if no constructor is defined
  • Default destructor, if not defined
  • Copy constructor, if not defined
  • Assignment operator, if not defined
  • Address operator, if not defined
  • Move constructor
  • Move the copy operator

① Assignment constructor

The assignment constructor is used to copy an object into a newly created object. That is, it is used during initialization (including passing parameters by value), rather than normal assignment: Class_name(const Class_name &); .

The copy constructor is called when a new object is created and initialized to an existing object of the same class

StringBad ditto(motto);             //calls StringBad(const StringBad &)
StringBad metoo = motto;            //calls StringBad(const StringBad &)
StringBad also = StringBad(motto);  //calls StringBad (const StringBad &)
StringBad * pStringBad = new StringBad(motto); //calls StringBad (const StringBad &)Copy the code
  • 1
  • 2
  • 3
  • 4

The copy constructor is used by the compiler every time the program makes a copy of an object. Specifically, the copy constructor is used when a function passes an object by value or when a function returns an object.

The default copy constructor copies non-static members one by one (member copy is also called shallow copy. Because the implicit copy constructor copies by value, instead of a string, it copies the value of a member

If a class has resources and the objects of the class are copied, the resources are reallocated, which is a deep copy; otherwise, the resources are not reallocated, which is a shallow copy. Because copy by value is just copying Pointers to strings, using strcpy() enables deep copy

② Assignment operator

Stereotype: Class_name & Class_name::operator=(const Class_name &), which accepts and returns a reference to an object of the class

Function: An overloaded assignment operator is used when assigning an existing object to another object

Since the default assignment operator is shallow copy, this will result in data corruption when the destructor is called. Solution: Provide assignment operator definitions (for deep copy)

  • Because the target object may reference previously allocated data, the function should be useddelete[]To release the data
  • Functions should avoid assigning objects to themselves; Otherwise, a free memory operation may delete the contents of an object before reassigning it
  • The function returns a reference to the calling object

C++11 NULL pointer: 0 or NULL or nullptr(official recommendation)

Static member functions: ① Cannot call static member functions from objects; Static member functions cannot use this pointer. ③ If a static member function is declared in the common part, it can be called using the class name and scope resolution operator

③ Matters needing attention

Note when using new:

  • If new is used in the constructor to initialize the pointer member, delete should be used in the destructor
  • New and DELETE must be compatible with each other. New corresponds to delete, new[] corresponds to delete[]
  • If you have multiple constructors, you must use new the same way, either with brackets or without them. Because there is only one destructor, all constructors must be compatible with it. However, it is possible to initialize a pointer with new in one constructor and null in the other, because DELETE can be used with null Pointers (but using delete for Pointers that are not initialized with new will be inconclusive and potentially harmful)
  • You should define a copy constructor that initializes one object to another through deep copy
  • You should define an assignment operator that copies one object to another by deep copy

Return object: If a function returns (by calling the object’s method or passing the object as an argument) to its object, it can be more efficient by returning a reference

  • Returning an object calls the copy constructor, and returning a reference does not
  • The object to which the reference points should exist when the calling function is executed
  • A reference declared as const must return const
  • If the returned object is a local variable in the called function, it should not be returned by reference because the local object will call its destructor when the called function completes execution

Pointers and objects

  • Declare a pointer to an object using normal pointer notation:String * first
  • We can initialize a pointer to an existing object:String * second = &saying[0];
  • We can initialize the pointer with new, which creates a new object:String * third = new String(sayings[choice]);
  • Using new on a class invokes the corresponding class constructor to initialize the newly created object
  • You can use->Operators access class methods through Pointers
  • Objects can be obtained by applying the dereference operator (*) to object Pointers

2. Class inheritance (common inheritance, protected inheritance, private inheritance)

1. Base and derived classes

① Constructors: Access permission considerations

Derived classes cannot access accumulated private members directly, but must access them through base class methods. When creating a derived object, the program first creates the base object. Conceptually, this means that the base class object should be created before the program enters the derived class constructor.

You can use the member initializer list syntax for derived class members, in which case you should use the member name in the list instead of the class name.

② Derived class:

  • First create the base class object
  • Derived class constructors should pass base class information to the base class constructor through the member initializer list
  • Derived class constructors should initialize new data members of derived classes
  • When creating a derived object, the program first calls the base class constructor and then the derived class constructor.
  • The base class constructor initializes the inherited data members; Derived class constructors are used primarily to initialize newly added data members
  • The constructor of a derived class always calls a base-class constructor. You can use initializer list syntax to specify which base-class constructor to use, otherwise the default base-class constructor will be used
  • When a derived object expires, the program calls the derived destructor first and then several more

You cannot assign a base class object or address to a derived reference or pointer.

  • Derived objects can use the methods of the base class, provided that the methods are not private
  • A pointer to a base class can point to a derived object without a display type conversion
  • A base class reference can refer to a derived object without a display type conversion

2. Polymorphic public inheritance: ① Redefining base class methods in derived classes ② using virtual methods (keyword virtual)

Virtual functions: :

  • Use keywords in base class methodsvirtualYou can make the method virtual in the base class as well as in all derived classes
  • If a virtual method is called with a reference or pointer to an object, the program uses the method defined for the object type, not the method defined for the reference or pointer type. This is called dynamic or late concatenation so that a base class pointer or reference can point to a derived class object
  • Those class methods to be redefined in derived classes should be declared virtual if the defined class is to be used as a base class

The compiler handles virtual function methods by adding a hidden member to each object that holds a pointer to an array of function addresses, called a virtual table. The virtual function table stores the addresses of the virtual functions declared for class objects.

Cost of using virtual functions in memory and execution speed:

  • Each object will grow, adding more space to store addresses
  • For each class, the compiler creates a virtual function address table (array)
  • For each function call, you need to do one additional operation, which is to look up the address in the table

Using virtual functions:

  • Constructors cannot be virtual functions. When a derived object is created, the constructor of the derived class is called
  • Destructors should be virtual unless the class does not use a base class (usually a virtual destructor is provided for the base class).
  • Friends cannot be virtual functions, because friends are not class members, and only class members can be virtual functions
  • If the derived class does not redefine the function, the base class version of the function is used; If a function is redefined in a derived class, the base class method with the same name is hidden, regardless of the parameter signature table.

    • If the inherited method is redefined, it should be exactly the same as the original prototype, but if the return type is a base class reference or pointer, it can be modified to a reference or pointer to a derived class. This feature is called return type covariant because it allows the return type to change with the class type
    • If the base class declaration is overloaded, all base class versions should be redefined in derived classes

Abstract base class: A virtual function containing =0 in a stereotype is pure virtual. A class containing a pure virtual function can only be used as a base class and can be redefined by ** more than one derived class: virtual double Area() const =0

3. Static and dynamic linking

Function name binding: Interprets a function call in the source code to execute a specific block of function code

  • Concatenation during compilation is called static concatenation or early concatenation (the compiler uses static concatenation for non-virtual methods)
  • The compiler must generate code that can select the correct virtual method while the program is running, known as dynamic or late binding

If you want to redefine a base class method in a derived class, set it to virtual

Upcast: Converts a derived class reference or pointer to a base class reference or pointer, which eliminates the need for display type casting for public inheritance. Downcast: converts a base class pointer or reference to a derived class pointer or reference. If display type conversions are not used, downward conversions are not allowed


3. Code reuse in C++

1. Private inheritance (with private inheritance, classes get implemented)

With private inheritance, both the public and protected members of the base class become private members of the derived class, meaning that the base class methods will not be part of the public interface of the derived object, but can be used in the member functions of the derived class.

Various inheritance modes

Characteristics of the Public inheritance Protect the inheritance Private inheritance
Public member becomes A public member of a derived class A protected member of a derived class A private member of a derived class
Protected members become A protected member of a derived class A protected member of a derived class A private member of a derived class
Private members become It can only be accessed through the base class interface It can only be accessed through the base class interface It can only be accessed through the base class interface
Can you implicitly convert up is Yes (but only in derived classes) no

Make base class methods that protect derived or private derived methods available outside of derived classes:

  • Define a derived class method that uses the base class
  • Wrapping a function call in another function call, using oneusingDeclaration to indicate that a derived class can use a particular base class member, even if the derivation is private

2. Multiple inheritance

① Virtual base class: make objects derived from multiple classes (their base class is the same) inherit only one base object

class Singer : virtual public Worker{.};
class Waiter : public virtual Worker{.};Copy the code
  • 1
  • 2

Worker is used as the virtual base class for Singer and Waiter

For non-virtual base classes, the only constructor that can appear in the initializer list is the immediate base class constructor

class A
{
    int a;
public:
    A(int n = 0) : a(n){}
    .
};
class B : public A
{
    int b;
public:
    B(int m = 0,int n = 0) : A(n),b(m){}
    .
};
class C : public B
{
    int c;
public:
    C(int q = 0,int m = 0,int n = 0) : B(m,n),c(q){}
    .
}Copy the code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

C constructors can only call B constructors, and B constructors can only call A constructors. Here the constructor of class C takes the value q and passes the values m and n to the constructor of class B; The constructor of class B takes the value m and passes the value n to the constructor of class A.

  • If a class has an indirect virtual base class, one of the virtual base class’s constructors must be explicitly called unless only the default constructor of the virtual base class is used
  • If the base class is virtual, the derived class will contain one child of the base class, and if the base class is not virtual, the derived class will contain multiple children
  • If a class inherits two or more members of the same name from different classes, using that member without qualifying it with the class name will result in ambiguity
  • A name in a derived class takes precedence over the same name in a direct or indirect ancestor class

Template

Implicit instantiation: They declare one or more objects, indicating the desired type, and the compiler generates concrete class definitions using the prescriptions provided by generic templates:

ArrayTP<int.100> stuff;     //implicit instantiationCopy the code
  • 1

The compiler does not generate an implicit instantiation of the class until the object is needed:

ArrayTP<double.30> *pt;         //a pointer,no object needed yet
pt = new ArrayTP<double.30>;    //now an object is neededCopy the code
  • 1
  • 2

When the template keyword is used and indicates the required type to declare a class, the compiler generates a display instantiation of the class declaration. template <> class Classname

{… } template

class Pair{… }