class

Like Java and other object-oriented language types, defining a class requires defining access modifiers, class members, and class functions

Member functions defined in the class definition declare functions inline, even without an inline identifier.

Members defined by class are private by default. Struct is public

class Box
{
   public:
      double length;   // The length of the box
      double breadth;  // Width of the box
      double height;   // Height of the box
      // Member function declarations
      double get(void);
      void set( double len, double bre, double hei )
};
Copy the code

Member functions can be defined externally

// Member function definition
double Box::get(void)
{
    return length * breadth * height;
}
Copy the code

The public data members of the objects of the class can be accessed using the direct member access operator

Access modifier

Access restrictions for class members are specified by marking each area public, private, and protected inside the body of the class.

  • Public Public members are accessible outside the class in the program
  • Private Private member variables or functions are not accessible outside the class; only class and friend functions can access private members.
  • Protected members are accessible in derived classes (subclasses).

The constructor

Used to assign/initialize attributes, just like Java constructors

#include <iostream>

using namespace std;

class Line {
public:
    int ac;

    void setLength(double len);
    double getLength(void);

    Line(double len, int a);  // This is the constructor

private:
    double length;

};

// Member function definition, including constructor
Line::Line(double len, int a) {
    cout << "Object is being created, length = " << len << endl;
    length = len;
    ac = a;
}

void Line::setLength(double len) {
    length = len;
}

double Line::getLength(void) {
    return length;
}

// The main function of the program
int main(a) {
    Line line(10.0.2);

    // Get the length of the default setting
    cout << "Length of line : " << line.getLength() << line.ac << endl;
    // Set the length again
    line.setLength(6.0);
    cout << "Length of line : " << line.getLength() << endl;

    return 0;
}
/*
Object is being created, length = 10
Length of line : 102
Length of line : 6
*/
Copy the code

Another way to write this is to initialize a field using an initializer list

Line::Line( double len): length(len)
{
    cout << "Object is being created, length = " << len << endl;
}
Copy the code

Assign len to length directly

Suppose you have a class C with multiple fields X, Y, and Z that need to be initialized. You can use the same syntax as above, but separate the fields with commas

C::C( double a, double b, double c): X(a), Y(b), Z(c)
{
  ....
}
Copy the code

Note that C++ initializes class members in the order they are declared, not in the order they appear in the initializer list. The wrong order may result in some variables not being assigned values, so the order of variables needs to be consistent.

The destructor

The destructor of a class is a special member function of a class that is executed each time the object created is deleted.

The name of the destructor is exactly the same as the name of the class, prefixed with a tilde (~), and it does not return any value, nor can it take any arguments. Destructors help free resources before exiting the program, such as closing files, freeing memory, and so on.

#include <iostream>
 
using namespace std;
 
class Line
{
   public:
      void setLength( double len );
      double getLength( void );
      Line(a);// This is the constructor declaration
      ~Line(a);// This is the destructor declaration
 
   private:
      double length;
};
 
// Member function definition, including constructor
Line::Line(void)
{
    cout << "Object is being created" << endl;
}
Line::~Line(void)
{
    cout << "Object is being deleted" << endl;
}
 
void Line::setLength( double len )
{
    length = len;
}
 
double Line::getLength( void )
{
    return length;
}
// The main function of the program
int main( )
{
   Line line;
 
   // Set the length
   line.setLength(6.0); 
   cout << "Length of line : " << line.getLength() <<endl;
 
   return 0;
}
Copy the code

Copy constructor

The copy constructor is a special constructor that initializes the newly created object with a previously created object of the same class. Copy constructors are usually used for:

  • An object is passed to the function body as a value
  • An object is returned from a function as a value pass
  • An object needs to be initialized by another object.

When a class member has a pointer type member that needs to be allocated memory, it is necessary to have a total definition copy constructor

The default copy constructor implements only a shallow copy, that is, copies the data members of the original object to the corresponding data members of the new object, without allocating additional memory resources for the new object.

Thus, if the object’s data member is a pointer, both pointer objects actually point to the same memory space. In some cases, shallow copy back can cause data security concerns.

When a class has a pointer type in its data members, we must define a special copy constructor that not only copies the data members between the original object and the new object, but also allocates separate memory resources to the new object. This is the deep-copy constructor.

If a copy constructor is not defined in a class, the compiler defines one itself. If a class has pointer variables and dynamic memory allocation, it must have a copy constructor.

classname (const classname &obj) {
   // Constructor body
}
Copy the code
#include <iostream>
 
using namespace std;
 
class Line
{
   public:
      int getLength( void );
      Line( int len );             // A simple constructor
      Line( const Line &obj);      // Copy the constructor
      ~Line(a);// destructor
 
   private:
      int *ptr;
};
 
// Member function definition, including constructor
Line::Line(int len)
{
    cout << "Call constructor" << endl;
    // Allocate memory for Pointers
    ptr = new int;
    *ptr = len;
}
 
Line::Line(const Line &obj)
{
    cout << "Call the copy constructor and allocate memory for pointer PTR" << endl;
    ptr = new int;
    *ptr = *obj.ptr; / / copy the value
}
 
Line::~Line(void)
{
    cout << "Free memory" << endl;
    delete ptr;
}
int Line::getLength( void )
{
    return *ptr;
}
 
void display(Line obj)// The copy constructor is called
{
   cout << "line 大小 : " << obj.getLength() <<endl;
}
 
// The main function of the program
int main( )
{
   Line line1(10);
 
   Line line2 = line1; // The copy constructor is called
 
   display(line1);
   display(line2);
 
   return 0;
}
/* Call the copy constructor and allocate memory line size to the PTR: 10 Release memory release memory release memory */
Copy the code

Note that memory was freed four times, indicating that the copy constructor was called to create a new object when the object was passed as a parameter

A friend function

A friend function of a class is defined outside the class but has access to all private and protected members of the class. Friend functions are not member functions, although their prototypes appear in class definitions.

A friend can be a function that is called a friend function; A friend can also be a class, which is called a friend class, in which case the entire class and all its members are friends.

To declare a function as a friend of a class, use the keyword friend before the function prototype in the class definition

#include <iostream>

using namespace std;

class Box
{
    double width;
public:
    friend void printWidth(Box box);
    friend class BigBox;
    void setWidth(double wid);
};

class BigBox
{
public :
    void Print(int width, Box &box)
    {
        // BigBox is a friend class of Box, which can directly access any member of the Box class
        box.setWidth(width);
        cout << "Width of box : "<< box.width << endl; }};// Member function definition
void Box::setWidth(double wid)
{
    width = wid;
}

// Please note that printWidth() is not a member function of any class
void printWidth(Box box)
{
    /* Because printWidth() is a friend of Box, it can directly access any member of the class */
    cout << "Width of box : " << box.width << endl;
}

// The main function of the program
int main(a)
{
    Box box;
    BigBox big;

    // Use the member function to set the width
    box.setWidth(10.0);

    // Use a friend function to print the width
    printWidth(box);

    // Set the width using the method in the friend class
    big.Print(20, box);

    getchar(a);return 0;
}
Copy the code

Inline function

C++ inline functions are commonly used with classes. If a function is inline, at compile time, the compiler places a copy of the function’s code wherever the function is called.

Any change to an inline function requires recompiling all clients of the function, because the compiler needs to replace all the code once again, or the old function will continue to be used.

If you want to define a function as inline, you place the keyword inline before the function name and define the function before calling it. If a function is defined with more than one line, the compiler ignores the inline qualifier.

Functions defined in a class definition are inline functions, even without the inline specifier.

The purpose of introducing the inline function is to solve the efficiency problem of function call in the program. When the program is compiled by the compiler, the compiler replaces the calling expression of the inline function with the function body of the inline function, while for other functions, they are replaced at runtime. It’s just a space cost over time I savings. So inline functions are usually small functions with lines 1-5. Be careful when using inline functions:

  • 1. Loop and switch statements are not allowed in inline functions;
  • 2. The definition of an inline function must appear before the first call of the inline function;
  • 3. The class in the class structure indicates that internally defined functions are inline functions.
#include <iostream>
 
using namespace std;

inline int Max(int x, int y)
{
   return (x > y)? x : y;
}

// The main function of the program
int main( )
{

   cout << "Max (20, 10) :" << Max(20.10) << endl;
   cout << "Max (0200)." << Max(0.200) << endl;
   cout << "Max (100101)." << Max(100.1010) << endl;
   return 0;
}
Copy the code

This pointer

Similar to languages such as Java, the this pointer refers to the object itself, and this is an implicit argument to all member functions

#include <iostream>
 
using namespace std;
 
class Box
{
   public:
      // Constructor definition
      Box(double l=2.0.double b=2.0.double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
      }
      double Volume(a)
      {
         return length * breadth * height;
      }
      int compare(Box box)
      {
         return this->Volume() > box.Volume(a); }private:
      double length;     // Length of a box
      double breadth;    // Breadth of a box
      double height;     // Height of a box
};
 
int main(void)
{
   Box Box1(3.3.1.2.1.5);    // Declare box1
   Box Box2(8.5.6.0.2.0);    // Declare box2
 
   if(Box1.compare(Box2))
   {
      cout << "Box2 is smaller than Box1" <<endl;
   }
   else
   {
      cout << "Box2 is equal to or larger than Box1" <<endl;
   }
   return 0;
}
Copy the code

Class pointer

A pointer to a C++ class is similar to a pointer to a structure. Accessing a member of a pointer to a class requires the member access operator ->, just like accessing a pointer to a structure.

#include <iostream>
 
using namespace std;

class Box
{
   public:
      // Constructor definition
      Box(double l=2.0.double b=2.0.double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
      }
      double Volume(a)
      {
         return length * breadth * height;
      }
   private:
      double length;     // Length of a box
      double breadth;    // Breadth of a box
      double height;     // Height of a box
};

int main(void)
{
   Box Box1(3.3.1.2.1.5);    // Declare box1
   Box Box2(8.5.6.0.2.0);    // Declare box2
   Box *ptrBox;                // Declare pointer to a class.

   // Save the address of the first object
   ptrBox = &Box1;

   // Now try using the member access operator to access the member
   cout << "Volume of Box1: " << ptrBox->Volume() << endl;

   // Save the address of the second object
   ptrBox = &Box2;

   // Now try using the member access operator to access the member
   cout << "Volume of Box2: " << ptrBox->Volume() << endl;
  
   return 0;
}
Copy the code

Static Static member

Static members are shared across all objects of a class. If no other initialization statement exists, all static data is initialized to zero when the first object is created. We cannot place the initialization of a static member in the class definition, but we can initialize a static variable outside the class by redeclaring it using the range resolution operator ::

Static member variables are only declared in a class and are not defined, so defining them outside the class actually allocates memory for static member variables. An error is reported if it is not defined. Initialization assigns an initial value and definition allocates memory.

#include <iostream>
 
using namespace std;

class Box
{
   public:
      static int objectCount;
      // Constructor definition
      Box(double l=2.0.double b=2.0.double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // Increment by 1 each time an object is created
         objectCount++;
      }
      double Volume(a)
      {
         return length * breadth * height;
      }
   private:
      double length;     / / the length
      double breadth;    / / width
      double height;     / / height
};

// Initializing a static member of the Box class is the process of defining and initializing it
int Box::objectCount = 0;
// It can also be defined this way but not initialized
//int Box::objectCount;
int main(void)
{
   Box Box1(3.3.1.2.1.5);    Box1 / / statement
   Box Box2(8.5.6.0.2.0);    / / declare box2

   // Outputs the total number of objects
   cout << "Total objects: " << Box::objectCount << endl;

   return 0;
}
/*
Constructor called.
Constructor called.
Total objects: 2
*/
Copy the code

Static members can be used anywhere, and static functions are similar

class Box
{
   public:
      static int objectCount;
      // Constructor definition
      Box(double l=2.0.double b=2.0.double h=2.0)
      {
         cout <<"Constructor called." << endl;
         // Increment by 1 each time an object is created
         objectCount++;
      }
      static int getCount(a)
      {
         returnobjectCount; }};// Initialize a static member of the Box class
int Box::objectCount = 0;
Copy the code

Class inheritance

They are called subclasses in Java and derived classes in c++

/ / the base class
class Animal {
    / / eat () function
    / / sleep () function
};
/ / a derived class
class Dog : public Animal {
    / / bark () function
};
Copy the code

Derived classes have access to all non-private members of the base class. So base class members that do not want to be accessed by member functions of derived classes should be declared private in the base class.

A derived class inherits all of the base class methods except for the following:

  • The base class constructor, destructor, and copy constructor.
  • An overloaded operator for the base class.
  • Friend functions of the base class.

Multiple inheritance

Multiple inheritance means that a subclass can have more than one parent class, which inherits the characteristics of more than one parent class.

#include <iostream>
 
using namespace std;
 
/ / base class Shape
class Shape 
{
   public:
      void setWidth(int w)
      {
         width = w;
      }
      void setHeight(int h)
      {
         height = h;
      }
   protected:
      int width;
      int height;
};
 
/ / PaintCost base class
class PaintCost 
{
   public:
      int getCost(int area)
      {
         return area * 70; }};/ / a derived class
class Rectangle: public Shape, public PaintCost
{
   public:
      int getArea(a)
      { 
         return(width * height); }};int main(void)
{
   Rectangle Rect;
   int area;
 
   Rect.setWidth(5);
   Rect.setHeight(7);
 
   area = Rect.getArea(a);// Output the area of the object
   cout << "Total area: " << Rect.getArea() << endl;
   // Output the total cost
   cout << "Total paint cost: $" << Rect.getCost(area) << endl;
 
   return 0;
}
Copy the code

Function overloading

Similar to Java, functions with the same name but different parameters are selected by the compiler by comparing the parameter types used with those in the definition.

The formal parameters of a function of the same name must be different in number, type, or order

      void print(int i) {
        cout << "The integer is:" << i << endl;
      }
 
      void print(double  f) {
        cout << "Floating point numbers are:" << f << endl;
      }
Copy the code

Operator overloading

You can redefine or overload most of the C++ built-in operators. This allows you to use operators of custom types.

Overloaded operators are functions with special names consisting of the keyword operator and the operator symbol to be overloaded after it. Like other functions, overloaded operators have a return type and a list of arguments.

Box operator+ (const Box&);
Copy the code

The declaration addition operator is used to add two Box objects and return the final Box object. Most overloaded operators can be defined as plain non-member functions or as class member functions. If we define the above function as a nonmember function of the class, then we need to pass two arguments for each operation

Box operator+ (const Box&, const Box&);
Copy the code

Operators defined inside classes usually operate using this, which is one of the purposes of operator overloading to manipulate objects

#include <iostream>
using namespace std;
 
class Box
{
   public:
 
      double getVolume(void)
      {
         return length * breadth * height;
      }
      void setLength( double len )
      {
          length = len;
      }
 
      void setBreadth( double bre )
      {
          breadth = bre;
      }
 
      void setHeight( double hei )
      {
          height = hei;
      }
      // Override the + operator to add two Box objects
      Box operator+ (const Box& b)
      {
         Box box;
         box.length = this->length + b.length;
         box.breadth = this->breadth + b.breadth;
         box.height = this->height + b.height;
         return box;
      }
   private:
      double length;      / / the length
      double breadth;     / / width
      double height;      / / height
};
// The main function of the program
int main( )
{
   Box Box1;                // declare Box1 of type Box
   Box Box2;                // declare Box2 of type Box
   Box Box3;                // declare Box3 of type Box
   double volume = 0.0;     // Store the volume in this variable
 
   / / Box1 elaborate
   Box1.setLength(6.0); 
   Box1.setBreadth(7.0); 
   Box1.setHeight(5.0);
 
   / / Box2 elaborate
   Box2.setLength(12.0); 
   Box2.setBreadth(13.0); 
   Box2.setHeight(10.0);
 
   // The volume of Box1
   volume = Box1.getVolume(a); cout <<"Volume of Box1 : " << volume <<endl;
 
   // The volume of Box2
   volume = Box2.getVolume(a); cout <<"Volume of Box2 : " << volume <<endl;
 
   // Add the two objects to get Box3
   Box3 = Box1 + Box2;
 
   // The volume of Box3
   volume = Box3.getVolume(a); cout <<"Volume of Box3 : " << volume <<endl;
 
   return 0;
}
Copy the code

Compound assignment operator refers to + =, * = – = this category from the basic arithmetic operators (+, -, *, /) or an operator (|, &, ~, etc.) = number of operators. They assign the result of the corresponding operation on the left and right operands to the left operator. For example: A += b; That means that a is equal to a plus b; The return value of the compound assignment operator, which defaults to an lvalue. A += b; In a.

When defining the compound assignment operator overload, note that the return value should be (* this) < class member > or the first left-hand operand < nonmember function >. For example :(assuming you have custom arithmetic or bitwise operators)

className & className::operator +=(className & right)
{
    return (*this) = (*this) + right;
}

className& operator +=(className& left, className& right)
{
    return left = left + right;
}
Copy the code

Polymorphism and virtual functions

Similar to Java, polymorphism means that when a member function is called, different functions are executed depending on the type of object on which the function is called. In simple terms, a subclass (derived class) object can be assigned to a reference variable of the parent class.

But unlike Java, c++ introduced the concept of virtual functions

#include <iostream> 
using namespace std;
 
class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0.int b=0)
      {
         width = a;
         height = b;
      }
      int area(a)
      {
         cout << "Parent class area :" <<endl;
         return 0; }};class Rectangle: public Shape{
   public:
      Rectangle( int a=0.int b=0) :Shape(a, b) { }
      int area (a)
      { 
         cout << "Rectangle class area :" <<endl;
         return(width * height); }};class Triangle: public Shape{
   public:
      Triangle( int a=0.int b=0) :Shape(a, b) { }
      int area (a)
      { 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); }};// The main function of the program
int main( )
{
   Shape *shape;
   Rectangle rec(10.7);
   Triangle  tri(10.5);
 
   // Store the address of the rectangle
   shape = &rec;
   // Call the rectangle area function
   shape->area(a);// Store the triangle address
   shape = &tri;
   // Call the triangle area function
   shape->area(a);return 0;
}
Copy the code

When the above code is compiled and executed, it produces the following results:

Parent class area :
Parent class area :
Copy the code

The reason for the error output is that the calling function area() is set by the compiler to a version in the base class, which is known as static polymorphism, or static linking – function calls are prepared before the program executes. This is sometimes referred to as early binding, because the area() function is set up during program compilation. That is, functions in the parent class are executed by default

In Shape, the area() declaration is preceded by the keyword virtual. Virtual functions are functions declared in the base class using the keyword virtual. When a virtual function defined in the base class is redefined in a derived class, the compiler is told not to statically link to the function. What we want is for any point in the program to be able to choose which function to call based on the type of object being called. This operation is called dynamic linking, or late binding.

class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0.int b=0)
      {
         width = a;
         height = b;
      }
      virtual int area(a)
      {
         cout << "Parent class area :" <<endl;
         return 0; }};/*
Rectangle class area :
Triangle class area :
*/
Copy the code

At this point, the compiler looks at the contents of the pointer, not its type. Therefore, since the addresses of tri and REc class objects are stored in * Shape, their respective area() functions are called. Note that the virtual function is declared in the parent class

That’s how polymorphism is used in general. With polymorphism, you can have multiple different classes, functions with the same name but different implementations, and even functions with the same parameters.

Pure virtual function

Pure virtual functions are used when a virtual function needs to be defined in a base class so that it can be redefined in a derived class to better fit objects, but there is no meaningful implementation of the virtual function in the base class. Similar to interfaces in Java. Attempting to instantiate an object of a pure virtual function without overriding it in a derived class results in a compilation error.

class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0.int b=0)
      {
         width = a;
         height = b;
      }
      // pure virtual function
      virtual int area(a) = 0;
};
Copy the code

Void funtion1()=0; Pure virtual functions must not be defined. Pure virtual functions are used to regulate the behavior of derived classes, called interfaces. Classes that contain pure virtual functions are abstract classes that cannot define instances, but can declare Pointers or references to concrete classes that implement the abstract class.

Virtual functions are declared as follows: Virtual ReturnType FunctionName(Parameter) Virtual functions must be implemented; if not, the compiler will report an error.

Virtual function table

The compiler creates a VTABLE for each class containing virtual functions. Each item in the table points to the address of a virtual function. That is, the VTABLE can be viewed as an array of function Pointers, and the entry address of each virtual function is an element of the array.

Each class that contains virtual functions has its own virtual table, VTABLE. The VTABLE of each derived class inherits the Vtables of its base classes. If the base VTABLE contains an item (the entry address of the virtual function), the VTABLE of its derived class also contains the same item, but the two items may have different values. If the virtual function corresponding to the item is overloaded in the derived class, the item of the derived class VTABLE points to the overloaded virtual function. If the virtual function corresponding to the item is not redefined in the derived class, the virtual function address of the base class is used.

When creating an object containing a class of virtual functions, the compiler adds a VPTR pointer to the VTABLE of the class to the memory layout of each object. When calling a virtual function via a pointer to a base-class object (set to BP), the compiler generates code to get the VTB1 pointer to the object and then call the corresponding item in the VTABLE of the class vtB1 points to (the entry address of the specific virtual function).

When no virtual function is defined in the base class, its length = the data member length; Length of derived class = length of its own data member + length of data member inherited from base class;

When a virtual function is defined in a base class, its length is equal to the length of the data member + the address length of the virtual function table. Derived class length = length of its own data members + length of data members inherited from the base class + address length of the virtual function table.

The length of a class containing one virtual function and several virtual functions is incremented by 0. Classes that contain virtual functions simply add a pointer to store the first address of the virtual function table.

Virtual functions whose derived class has the same name as the base class have the same index number (or ordinal number) in the VTABLE.