Bo2SS

Bo2SS

1 Classes and Objects

Course Content#

Types and Variables#

Can be understood as aliases for classes and objects

  • image-20210723211429904
  • C++ only specifies the minimum bit size for types, so some compilers can implement larger sizes

Types#

= Type Data + Type Operations

  • For example: int = 4-byte size data + basic operations (+-*/%), can be associated with data structures, int and double types are essentially data structures
  • Type data + type operations ➡️ member attributes + member methods
    • Can be understood as an enhanced version of C language struct (can hold attributes, but cannot hold methods)

Access Permissions

First distinguish between concepts inside and outside the class

Access permissions are set within the class, controlling whether the outside can access the inside

  • public: public
    • Can be accessed both inside and outside the class
  • private: private
    • Only methods within the class can access it
  • protected: protected
    • Besides the class itself, inherited classes can also access it
  • friendly: friend
    • Functions modified by it can access private and protected members within the class

Constructors and Destructors#

Object lifecycle: construct → use → destruct

Three Basic Types of Constructors#

Associating with local variable initialization, objects also need initialization

Constructor TypeUsage⚠️Note
Default ConstructorPeople bob;
Prototype: People();
1. Zero-parameter constructor
2. Automatically generated by the compiler
Conversion ConstructorPeople bob("DoubleLLL");
Prototype: People(string name);
1. A parameterized constructor with one parameter
2. This parameter is passed to the class's member variable and is not a const reference of the class itself
[PS] Similar to implicit type conversion
Copy ConstructorPeople bob(hug);
Prototype: People(const People &a);
1. A special parameterized constructor, the argument is an object of the same class
2. Not equivalent to the assignment operator "="
[PS] Easier to handle as const &

Destructor#

Destroying an object

Prototype: ~People();

⚠️Note:

  1. No parameters and no return value

  2. Used for resource recovery

Summary#

Both have no return value, and the function name is the same as the class name

  • In engineering development, the functions of constructors and destructors are designed to be very simple
    • ❓ Why not perform a lot of resource allocation in the constructor?
    • Reason: Bugs in constructors are difficult for the compiler to detect
    • Solution: Pseudo constructors, pseudo destructors; Factory design pattern
  • [+] Move Constructor (another key constructor, to be learned later)
    • From the C++11 standard——the standard that brought C++ back to prominence
    • Before this, STL had poor performance due to C++'s language characteristics, which did not distinguish between lvalues and rvalues, leading to a large number of copy operations, especially deep copy operations, significantly affecting performance
    • After this, the concept of rvalues was introduced, along with move constructors

Return Value Optimization (RVO)#

The compiler has RVO enabled by default

Introduction#

Object a is constructed through the return value of fun()

image-20210723211452133

Output result:

image-20210723211500226
  • Theoretically: should output 1 time transform and 2 times copy
    • See detailed analysis below 👇
  • In practice: no copy output, and the value of a.x is the x value from the temp object, meaning the address of the local variable temp was directly used as the address of object a (the data area of object a was allocated first, see below)
    • temp is more like a reference
    • Compiler optimization exists, i.e., return value optimization RVO🌟

Detailed Analysis#

Object initialization process: 1. Allocate object data area ➡️ 2. Match constructor ➡️ 3. Complete construction

  • After understanding the object initialization process, analyze the construction process in the above code:
    • image-20210723211510540
    • First, allocate the data area for object a
    • Then, enter the func function, allocate the data area for object temp, and initialize the local variable temp through "conversion constructor"——A temp(69);
    • Next, use "copy constructor" to copy temp to a temporary anonymous object and destroy object temp——return temp;
    • Finally, use "copy constructor" to copy the temporary anonymous object to a, destroying the temporary anonymous object——Aa = func();
    • 👉 Thus, the process includes 1 conversion constructor and 2 copy constructors
  • Compiler optimization
    • First optimization cancels the first "copy constructor", directly copying temp to a (optimization under Windows)
    • Second optimization cancels the second "copy constructor", making temp point to a directly (optimization under Mac and Linux)

Turning off RVO#

Compile the source file with g++ -fno-elide-constructors to turn off RVO

image-20210723211519691
  • Two additional "copy constructors" appeared, see detailed analysis above

Points to Note#

  • The compiler essentially implements RVO by replacing the this pointer
  • Because the compiler generally optimizes copy constructors, do not change the semantics of the copy constructor in engineering development
    • That is: only perform copy operations in the copy constructor, and do not perform other operations
    • For example: adding 1 to the copied attribute in the copy constructor does not conform to the semantics of the copy constructor, and if the compiler optimizes away the copy constructor, the result will be inconsistent with before optimization

+ Optimization of Assignment Operations#

RVO also exists——optimized one copy constructor, i.e., copying the local variable to a temporary anonymous object

image-20210723211527733
  • Added the code in the red box
  • Result before optimization:
    • image-20210723211535203
    • 1 "conversion constructor" + 1 "copy constructor"
  • Result after optimization:
    • image-20210723211540883
    • 1 "copy constructor"

+ Analysis of Copy Constructor Calls#

How is the copy constructor called under various writing methods?

Scenario: Class A contains an object d of a custom class Data, the red box is the added code

image-20210723211549347

「Mainly focus on line 29; turn off RVO compilation, otherwise the copy constructor will be skipped」

  1. Custom copy constructor, and explicitly copy each member attribute, i.e., line 29 remains unchanged
  • image-20210723211557942
  • When constructing object d, the copy constructor of the Data class will be called
  1. Custom copy constructor, not explicitly copying each member attribute, i.e., remove ",d(a.d)"
  • image-20210723211603337
  • When constructing object d, the default constructor of the Data class will be called (if not explicitly copied during customization, it matches the default constructor)
  1. Not customizing the copy constructor, the compiler automatically adds the default copy constructor, i.e., remove lines 29-31
  • image-20210723211610555
  • When constructing object d, the copy constructor of the Data class (compiler default) will be called

Conclusion:

❗️To achieve the expected result, when customizing the copy constructor, each member attribute should be explicitly copied

  • If the custom copy constructor does nothing, then that function will do nothing

Other Knowledge Points#

References#

A reference is an alias for the bound object

  • ❗️References need to be initialized at the time of definition, i.e., binding to an object, such as:
    • People a;
    • Initialize at definition: People &b = a;
    • Otherwise: People &b; b = c; will cause ambiguity——binding object or assignment?

Class Attributes and Methods#

With the static keyword
Different from member attributes (unique to each object) and member methods (this pointer points to the current object)

  • Class Attributes: Attributes shared by all objects of the class
    • Globally unique, shared
    • For example: the number of all humans——the number of all objects in humanity
  • Class Methods: Methods that do not belong to a specific object
    • Not bound to objects, cannot access this pointer
    • For example: testing whether a certain height is a legal height

const Methods#

Do not change the object's member attributes, cannot call non-const member functions

  • Provided for const objects (none of its attributes can be changed)

⚠️:

mutable: mutable, its modified variable can change in const methods

default and delete#

Control of default functions, C++11

  • default: Explicitly use the rules provided by the compiler by default
    • Only applicable to special member functions of the class (default constructor, destructor, copy constructor, copy assignment operator), and this special member function has no default parameters
    • ❗️This feature has no functional significance; it is C++'s design philosophy: focus on readability, maintainability, etc.
      • Understanding this philosophy can enhance one's aesthetic standards in C++
  • delete: Explicitly disable a certain function

struct and class#

  • struct
    • Default access permission: public (blacklist mechanism, needs to explicitly define private members)
    • Also used to define classes, with member attributes and methods, to distinguish from C
  • class
    • Default access permission: private (whitelist mechanism: needs to explicitly define public members)

❓: Why does C++ retain the struct keyword? Why is the default permission public?

  • All for compatibility with C language, which can reduce the difficulty of promotion

PS: Front-end language JavaScript reduces promotion difficulty by riding on Java's popularity, which is essentially unrelated to Java

Code Demonstration#

Example of a Class#

image-20210723211620159
  • It is recommended to separate the declaration and definition of attributes and methods in the class
  • The this pointer is only used in member methods, pointing to the address of the current object

Simple Implementation of cout#

image-20210723211627367
  • cout is an object, a high-level variable
    • Returning its own reference allows for chaining cout, the reason for using references will be understood later
    • Strings need to be received with const type variables, otherwise there will be warnings, as strings are literals
  • The essence of namespaces: the same object name can exist in different namespaces

Constructors and Destructors#

image-20210723211634762 image-20210723211642463

Running result:

image-20210723211648649

1) Discussion on Destruction Order#

  • image
  • Construction order: object a, object b
  • Destruction order: object b, object a
  • ❓ Why is the order of destructor calls reversed? Is it due to a compiler-generated special case, or is it a normal language feature? 👉 Language feature
    • The construction of object b may depend on information from object a ➡️ during destruction, object b may also need information from object a ➡️ object b must be destructed before object a
    • ❗️Who constructs first, destructs last
    • PS
      • This is unrelated to whether objects are placed in heap space or stack space; experiments show that the destruction order is always reversed
      • Can be considered a kind of topological order

2) Conversion Constructor#

  • ❓ Why is it called a conversion constructor (constructor with a single parameter)?
    • It converts a variable into an object of that type
  • 🌟 a=123 involves operator overloading: implicit type conversion ➡️ assignment ➡️ destruction, see code for details

3) Copy Constructor#

  1. Add reference: Prevent infinite calls to the copy constructor
  • ❗️If the copy constructor is: A(A a) {}, then A b = a; will occur,
  • Because [parameter a] is not a reference (pass by value), it first needs to copy [object a] to [parameter a] to generate a temporary object
  • At this point, the copy constructor will occur again, and this copy constructor will also go through the above process
  • Thus, infinite recursion occurs
  • PS: References do not produce any copy behavior, and are more convenient than pointers
  1. Add const: Prevent const type objects from using non-const type copy constructors, resulting in an error
  • Also prevents the copied object from being modified

Note:

  • When defining an object, "=" calls the copy constructor, not the assignment operation, for example, A b = a

4) Reflection#

  • When is an object considered constructed?
    • 「Refer to the code, using the default constructor as an example」
    • Functionally, the construction [logically]: by line 46, the constructor appears to have completed execution
    • Compiler's construction [actually]: by line 39, the object's members can already be called❗️🌟
  • Through the code in the reflection section, it can be understood:
    • Scenario: Adding a parameterized constructor in class Data causes the default constructor added by the compiler to be deleted
    • Process: When generating an object of class A, member attributes Data class objects p and q need to have completed construction, while the default constructor of Data class has been deleted
    • Result
      • If p and q are not initialized using an initializer list, an error will occur
      • If initialized using an initializer list, it is feasible; the initializer list belongs to what the compiler calls construction
    • ❗️This indicates that the compiler's construction is completed after the function declaration (line 39)
  • ⚠️:
    • The compiler will automatically add default constructors and copy constructors
    • Construction behavior should be placed in what the compiler calls construction, such as using initializer lists

+) Lvalue References#

  • To be learned later

+) Friend Functions#

  • Declared within the class (also ensuring it is approved by the class's manager)
  • Implemented outside the class, essentially a function outside the class but can access private member attributes within the class

Deep Copy, Shallow Copy#

Copying objects: arrays

image-20210723211710169
  • The copy constructor automatically added by the compiler is a shallow copy
    • For pointers, it only copies the address, so modifications to the copied object will modify the original object
  • Custom deep copy version of the copy constructor
    • For pointers, copy the value at the pointed address
    • PS: Constructors are only called during initialization; there is no behavior of copying themselves

⚠️:

  • To adapt to the overloaded "<<" with const parameters, it is necessary to implement the const version of "[]" overload
  • The end in the Array class has no relation to the end data of the array; it is just used to monitor array out-of-bounds situations

Analysis of Differences Between new and malloc#

image-20210723211717190

Running result:

image-20210723211724784
  • Both malloc and new can allocate space, corresponding to free and delete (if it is an array, then delete[]) to destroy space
  • new automatically calls the constructor, and the corresponding delete automatically calls the destructor; while malloc and free do not
  • malloc + new can achieve in-place construction, commonly used in deep copying, where new can also correspond to constructors of different classes

Class Attributes and Methods, const, mutable#

image-20210723211734657
  • Class attributes: declared with static in the class, initialized outside the class without static
  • Class methods: can be called in two ways, either through an object or the class name
    • Therefore, methods called by objects are not necessarily member methods; they can also be class methods
  • const: const objects can only call const methods, and const methods can only call const methods
  • mutable: its modified variable can change in const methods

default, delete#

Functional Requirement: Prevent objects under a certain class from being copied

image-20210723211742795
  • Disable copy constructors and assignment operators
    • Copy constructor: set to =delete, or place it in private access
    • Assignment operator overload function: also set to =delete (never allow assignment operations), or place it in private access (only methods within the class can use assignment operations)
    • PS: The assignment operator must consider both const and non-const versions
  • ❓ To truly prevent an object from being copied, both the copy constructor and assignment operator overload should be set to =delete; otherwise, methods within the class can still copy that object

Additional Knowledge Points#

  • Curly braces after the constructor
    • Adding curly braces indicates it is a function implementation
    • Not adding curly braces means it is just a function declaration, and a dedicated implementation still needs to be written

Points to Consider#

  • Pay attention to many things the compiler does by default; this is the complex part of C++

Tips#

  • C++
    • Learning Method: Learn categorically according to programming paradigms
    • Learning Focus: The processing flow of programs [far more complex than C]

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.