c++ class

c++ class

Basic knowledge

  1. Objects without any attributes or methods only occupy one byte . When there are attributes and methods, another byte will not be allocated. Member functions will not be counted in the space occupied by the class. Only non-static member variables belong to objects of the class.
    //This type of object only occupies 4 bytes: the bytes occupied by int a class Demo { public : int a; void test () {}; }; Copy code
  2. The instantiation is completed when the variable is declared, and the no-argument constructor is called at this time . The following class names are all Demo as an example
  3. The definition of access permissions is public: followed by the attributes and methods of the corresponding permissions . There are three types of access permissions: public, protected, and private, and the meaning is similar to java
    //Define the class Demo { public : //The following content defines the attributes and methods of public permissions int a; int getA () { return a; } private : //Define private properties and methods int b; }; int main ( int argc, const char * argv[]) { //instantiate a Demo object Demo d; //Assign da = 20 to the attributes of the Demo object ; //call the methods in the Demo cout << da << endl; return 0 ; } Copy code
  4. Compared with struct: the default permission of the class is private, the default permission of the structure is public, there is no difference except that
  5. this is the pointer of the current object. Its essence is a pointer constant . When referring to the properties and methods of the current object through this, it must be written in the form of a pointer
  6. Null pointers can access member functions and methods, as long as the method does not use the properties and methods related to the specific object
  7. The function in the class can only be declared and implemented outside the class, just use :: to add scope
    class Test { public : Test ();//The constructor can be implemented outside the class //declare void test () ; static void test2 () ; }; //Test:: is equivalent to telling the compiler that it is a function in the Test class void Test::test () { cout << "from outer" << endl; }; Test:: Test (){ cout << "Constructor" << endl; } void Test::test2 () { cout << "Static function" << endl; } Copy code

Inner class

  1. Within one class, another class can be defined, and the scope of the external class should be used when referencing
class Demo { public : class Demo2 { public : int a; }; }; //Use inner class Demo::Demo2 d2; Copy code
  1. In addition to being directly defined inside the class, the inner class can also be used to refer to the class defined outside the class through typedef
    class Test { public : int a; }; class Demo { public : //Rename the Test class typedef Test dt; }; //The alias is used when using Demo::dt d2; Copy code

head File

In general, the class declaration is in the header file, and the implementation is in the cpp file :

  1. In the header file, define the properties and methods of the class, and then delete the method body
  2. In the cpp file, you only need to write the implementation of the class method. Note: You must use :: to specify the scope of the current method
  3. The private attributes and methods defined by the header file can be used in the cpp file
// # include <iostream> in the header file //Define the class class Demo { public : int demo () ; //Declare the method without writing the method body private : int a; } // # include "test.h" in the cpp file //Specify the demo method by Demo:: to be the method declared in the Demo class //No need to write class Demo in the cpp file, just pass :: to achieve the declaration in the header file The method can be int Demo::demo () { return Demo::a; //Use the private attribute defined in the header file } Copy code

Constructor and destructor

The destructor is called by the compiler before the object is destroyed to perform some cleanup work . The call order of destructor is opposite to the call order of constructor

  1. Java constructor and similar, by the class name () {} define a constructor, the constructor parameter may be added
  2. Destructor definition: ~Demo(){} , that is, add the ~ symbol in front of the class name
    • The destructor will only be called once, before the object is destroyed
    • Destructor can not define parameters
    //Call the parameterless constructor //Cannot be written as Demo d() Demo d; //Call the parameterized constructor Demo d1 ( 1 ) ; copy the code
  3. If class A has class B attributes. By calling the constructor of B first, then calling A's; when destructuring, calling A's first and then B's

Constructor call

There are three ways to call the constructor:

  • When declaring a variable, directly add parentheses after the variable to call . For example, Demo d(10) will call the constructor with an int parameter
  • Similar to java call , except that the new keyword is not written. Such as Demo d = Demo(10)
  • Direct assignment , that is, write the parameter directly to the right of the equal sign. For example, Demo d = 10 , it will call the constructor with only int parameters
  • The braces are initialized . When the class or structure does not have a constructor, the list elements will be provided in the order in which the members are declared in the class, which can be written less, but the position cannot be wrong . If the class has a constructor, provide the elements in the order of the parameters
    class class_d { public : float m_float; string m_string; wchar_t m_char; }; int main () { //Initialize in the order of attribute declaration class_d d1{}; class_d d1{ 4.5 }; class_d d2{ 4.5 , "string" }; class_d d3{ 4.5 , "string" , 'c' }; class_d d4{ "string" , 'c' }; //compiler error, the order is wrong class_d d5{ "string" , 'c' , 2.0 }; //compiler error, the order is wrong } Copy code

Copy constructor

In Demo (const Demo & d) constructor defined in the form called copy constructor

  1. When an object is passed as an actual parameter to a function, or when the function returns a local variable object, the copy constructor is called . Because C++ is passed by value, the actual parameters are copied, and the formal parameters point to the copied object
  2. When an anonymous object calls the constructor, the copy constructor cannot be called
  3. The copy constructor added by the compiler by default will copy all attributes

Default constructor

After defining a class, the compiler will add three functions by default: the default constructor, the default destructor, and the default copy constructor

  1. When the parameter constructor is explicitly defined, the compiler will not add a default constructor, but will add a copy constructor
  2. When the copy constructor is explicitly defined, the compiler will not add the constructor

Initialization list

The initialization of the property is placed after the constructor, not in the body of the function

There are two ways of writing, one is to specify the default value directly, and the other is to pass the default value through a parameter. The specific format is Demo():a(initValue){} , where a is the attribute defined in Demo

class Test { public : //Initialize the two attributes a and b. The program directly specifies the default value Test (): a ( 10 ), b ( 20 ){}; //Specify the default value //Mid-term a is specified by the caller, and b is specified by the program itself Test ( int a): a (a) , b ( 20 ){}; int a; int b; }; Copy code

Since the constructor can be called directly by assignment , the following is correct:

class T2 { public : T2 (string name){}; }; class Test { public : //The initialization list is equivalent to T2 t2 = name;, according to the third method to call the constructor Test (string name): t2 (name)(); T2 t2; }; Copy code

Static properties and methods

Add static before methods and properties, and the corresponding methods and properties are static methods and static properties.

Similar to java, static properties and methods belong to the class and are shared by all objects

  1. By Demo :: staticFun/staticProperty call static methods, properties form
  2. Static properties must be declared inside the class and initialized outside the class
class Demo { public : static void test () { cout << "static fun " << a << endl; }; //Static properties, declare static int a in the class ; }; //Static property, initialization outside the class //Must use :: specify the class to which the property belongs int Demo::a = 20 ; copy the code

this

this is a pointer to the current object . Its essence is a pointer constant , that is, the point of this cannot be modified

  1. Because this is a pointer, the property and method of using this to refer to the object must be in pointer mode

  2. When returning the current object, use the *this syntax

    class Demo { public : int a = 10 ; //Here you can directly return to Demo, or you can return to reference Demo& //Only the former returns a copy of the current object, the latter returns the current object itself Demo& test ( int a) { //Refer to the object attribute in the form of a pointer a cout << this -> a << endl; //Use *this to return the current object return * this ; }; }; Copy code

Null pointer

Null pointers can access object methods, but this method cannot be used to refer to properties and methods related to specific objects

In other words, a null pointer can use static methods and properties, but cannot use member methods and properties

class Demo { public : static int b; int a = 10 ; void test () { //The output can be executed normally cout << "test" << b << endl; }; void test2 () { //An error will be reported. Because a needs a specific object, the null pointer has no specific object cout << "test" << a << endl; } }; //call method Demo* dp = NULL ; dp-> test (); dp-> test2 (); Copy code

Constant function

The function modified by const is a constant function

The format of a regular function is: put const before the curly braces of the method body, such as void test() const{}

  1. The member variable can not be modified in the constant function, but the static variable can be modified, so the static variable is not referenced by this . A constant function is equivalent to using const before this, and this is essentially a pointer constant. After being modified by const, this is both a constant pointer and a pointer constant, so the method body cannot be modified by this
    • In other words, const actually modifies this in the member function
  2. If you want to modify a member variable in a regular function, you need to add the mutable keyword before the variable , such as mutable int b;, the b attribute can be modified in the regular function

Regular object

Modified with const before the object , it is a constant object

  1. Examples of constant objects such as const Demo d
  2. Constant objects are not allowed to modify member attributes, except for attributes modified by mutable
  3. Ordinary objects cannot call extraordinary functions . Assuming that ordinary functions can be called, the properties may be modified in ordinary functions, which is equivalent to that a constant object can indirectly modify member properties, which is not consistent with the second

Friends

Friends: A class or method that can access private members of a class . The private members of ordinary classes cannot be accessed by the outside world. You can specify several classes and methods through friends to access its private

  1. The friend is defined by the key friend, and the friend needs to be written in front of the class
  2. Global functions can be used as friends . Copy the declaration of the method to the class and add the friend keyword in front
    class Demo { //Define friends. friend void test (Demo& d2) ; }; Copy code
  3. One class can be a friend of another class
    class Demo { friend void test (Demo& d2) ; //Declare Test as a friend of the current class, then in the Test class you can access the private member friend of Demo class Test ; private : int a = 10 ; }; Copy code
  4. You can also declare a function of the class as a friend . Assuming there are two classes: Test and Demo, Demo needs to declare Test::test() as its own friend, then
    • The Demo class needs to be declared first, so that the Demo class can be used when the Test is declared
    • Then declare the Test class, so that the Test class can be used when defining friends in the Demo
    • Implement the Demo class
    • Implement the Test::test method
    class Demo ; //Declare the Demo class class Test { public : //Declare the Test class, use the Demo class just declared void test (Demo* d) ; }; //Implement the Demo class class Demo { public : //Define friends. Test::test ensures that test is in the Test class, not the global function friend void Test::test (Demo* d) ; private : int a = 10 ; }; //Implement the test method again void Test::test (Demo *d) { cout << d->a << endl; } Copy code

Operator overloading

Similar to kt, except that the overloaded method name is different. The commonly used cout<< is operator overloading . Don't abuse operator overloading

There are two types of overloaded methods: one is defined in the class; the second is defined as a global method . See the example below for specific definition details

  1. Defined inside the method, only one parameter is required
  2. Defined as a global method, it requires references to two objects, respectively representing the elements involved in the operation
  3. An operator can be overloaded multiple times to perform operations on different parameters
  4. Operator overloading is essentially calling the corresponding method . For example, A+B, equivalent to A.operator+(b) or operator+(A,B)

The overloaded method names and corresponding operators are summarized as follows:

Method nameOperatorExample of overloaded method
operator++ SignTest operator+(Test& t1,Test& t2)
operator<<<< Left shift operatorTest& operator<<(Test& t1,Test& t2)
operator++Pre-increment operator, such as ++aTest& operator++()
operator++(int)Post-increment operator, such as a++Test operator++(int)
operator=Assignment operatorTest& operator=(Test& p)
operator==== overloadbool operator==(Test& t)
operator()Function call operatorvoid operator()(string test)/int operator()(int a,int b)

Talk about the overload of the left shift operator , the left shift operator needs to use the global function overload . We often use cout << "11", essentially because the system defines the left shift operation of cout and string, that is, the operator<<(cout,string) method is overloaded. But there is no way to use cout << Demo directly , because there is no corresponding overload of the left shift operator in the system. In order to implement this function, the program needs to be overloaded.

The distinction between pre- and post-operator is to pass in the int placeholder in the overloaded method. Note: You can only pass in int here, not other types

The rest of the relational operators are similar to operator==, you only need to replace the following == with the corresponding operator. For example, operator!= is used to overload the != operator

The function call operator allows an object to be called directly like a function . As in the above example, you can directly use a("xx"), where a is the corresponding object. And the method parameters of the function call overload are very arbitrary, not necessarily defined as the string in the example

Examples of overloading are as follows:

//Overload + operator //Overload writing defined in the class Test operator +(Test& t2){ Test t = this ->a + t2.a; return t; }; //Define another overload. This overload ensures that the Test object can be added to int Test operator +( int a){ Test t = this ->a + a; return t; } //Defined as the overloading of your global method //Need two object references Test operator -(Test& t1,Test& t2){ Test tmp = t1.a-t2.a; return tmp; } Copy code

Front-rear

  1. Be sure to remember: the reference to the object is returned in the front, and the object is returned in the back . The main purpose of this return is: the front result is modified, using the new and old to participate in the operation; the rear result is unmodified, using the old value to participate in the operation, but the value of the current object is the new value
  2. **The rear is distinguished from the front by passing int in the overloaded method
class Test { public : int a = 10 ; //Preface, return reference Test& operator ++(){ this ->a ++; //Return the current object, whose value is the modified value return * this ; }; Test operator ++( int ){ //tmp points to a copy of the current version of this Test tmp = * this ; //The current value in this is modified, but the value in tmp is still the old value this ->a++; //return tmp, that is, the old value is returned return tmp; } }; Copy code

inherit

Basic

  1. Grammar class Subclass: [Inheritance] Parent class
  2. There are three ways of inheritance in c++: public, protected, and private. The inheritance method mainly deals with what kind of access authority the members inherited by the subclass from the parent class have, and it is taken according to the lowest principle . If the inheritance method is private, the access rights of all members inherited by the subclass are private, regardless of whether the parent class is public or protected
  3. The child class inherits all the members of the parent class, including private members, but the private members cannot be accessed . In the following example, sizeof(C) = 12, indicating that C has inherited the private b attribute of the parent class, but it is not accessible in C
    class P { public : int a; private : int b; }; class C : public P{ public : int c; }; Copy code
  4. You can get through 3: All attributes of the parent class will be copied to the subclass, and the private attribute will be hidden by the compiler, so the subclass cannot
  5. Execute the parent class constructor first, and then execute the subclass constructor; the destructuring execution order is opposite to the construction order
  6. When the subclass and the parent class have attributes with the same name, the subclass will not overwrite the properties of the parent class
    • To access the subclass's own attributes, use sp , s represents the subclass object, and p represents the subclass attribute
    • To access the properties of the parent class, use s.Parent::p , where Parent represents the name of the parent class
  7. When the child class and the parent class have methods with the same name, the processing method is the same as 6. But one thing to note is that the same-named method of the subclass will overwrite all the same-named methods of the parent class, regardless of whether their method signatures are the same, as long as the method names are the same, they will be overwritten
    class P { public : void test () { cout << "p test" <<endl; } void test ( int ) { cout << "p test int" <<endl; } }; class C : public P{ public : void test () { cout << "c test" <<endl; } }; int main ( int argc, const char * argv[]) { C c; c. test (); //Compile error, because c.test covers the method in P c. test ( 11 ); return 0 ; } Copy code
  8. Static members are handled in the same way as non-static members. Subclass refers to the static member variable of the parent class by the class name: C::P::a , the basic C is the subclass name, C:: refers to the member variable by the class name, followed by P::a refers to the parent class A in

Multiple inheritance and virtual inheritance

c++ allows multiple inheritance, but not recommended

  1. The syntax is: class subclass: inheritance parent class 1, 2 ... parent class inheritance . Similar to single inheritance, except that other parent classes are added after the parent class
  2. Diamond inheritance: A is the parent class, B and C are its subclasses, and D inherits B and C. Now the four classes will form a diamond-shaped inheritance . Diamond inheritance will cause two copies of the data in the parent class to be stored in the subclass, that is, two copies of the data in A are stored in D.

In order to solve the above problems, virtual inheritance is introduced: mainly used to solve the space waste and data ambiguity caused by diamond inheritance

Let's talk about the ambiguity of data: because D inherits the members of A from B and C respectively, any member of D used in A will have ambiguity: I don't know which one to point to.

  1. Virtual inheritance members only store a copy of A, while B/C inherited members point to Part D in its own storage .
  2. The wording of virtual inheritance: add virtual before the inheritance method , such as class C: virtual public A

Polymorphism

Virtual function

Functions modified by virtual are virtual functions . The virtual function is mainly used to implement polymorphism, which allows this function of the subclass to be called with the pointer/reference of the base class .

A virtual function is not a function without a method body, it is completely different from the abstract function in java.

Pure virtual function

Abstract function in java

  1. The syntax format is: virtual void test2()=0;, that is, return 0 directly after the virtual function
  2. Classes with pure virtual functions are abstract classes, and abstract classes cannot be instantiated directly. As long as the subclass rewrites the pure virtual function, the subclass can be instantiated

Polymorphic syntax

Polymorphism in c++ is similar to java. In the following code, P represents the parent class and C represents the subclass:

  1. Polymorphism calls the method of the parent class
    P = P C (); //call the method using p, P is defined in the call in, rather than the method of C copy the code
  2. In order to solve the problem in 1, it is necessary to use the reference or pointer of the parent class to point to the instance of the subclass, and the method is defined as a virtual method, which is modified by virtual. If the latter is missing, the method defined in P is still called
    C c; P& p = new C; . P Test (); //call at this time is as defined in method C //or P * = P new new C; //pointer to the instance of a subclass using p-> Test (); duplicated code

Fictitious Destruction and Pure Fictitious Destruction

In polymorphism, the parent class pointer will not call the subclass's destructor when it is destructed

  1. Replacing the example in polymorphism, P will not call the destructor of C when it is destructed, which leads to memory leaks in the objects allocated in the heap memory in C. To solve this problem , the destructor of the parent class needs to be defined as a virtual function

    //Define virtual destruction virtual ~ P (){ } Copy code
  2. Pure fictitious analysis is to resolve the same problems as fictitious analysis, the only difference between the two is grammatical. Pure fictitious destruction is first declared in the class, and then the implementation is written outside the class

    class P { public : //Define pure virtual destruction virtual ~ P () = 0 ; }; //The implementation of pure virtual destruction must be written outside the class P::~ P (){ cout << "P pure fictitious destruction" << endl; } Copy code

Function object

Classes overloaded with function call operators are called function objects

  1. Function objects can be called like functions, such as P p; p() . Functor
  2. A functor that returns a bool type is called a predicate. Those that require one parameter are called unary predicates, and those that require two parameters are called binary predicates.