Inheritance and derivation

C ++ is object-oriented programming, so as long as object-oriented, will have polymorphic, inherited characteristics. How does C++ implement inheritance? Look at the following section. Inheritan**ce ** can be understood as the process by which one class obtains member variables and member functions from another class. For example, class B inherits from class A, then B has member variables and member functions of A.

Derive ** is the same concept as inheritance in C++, just from a different perspective. Inheritance is the son taking over the father’s property, and derivation is the father passing on the property to the son.

An inherited class is called a parent or base class, and an inherited class is called a subclass or derived class. “Subclasses” and “parent classes” are often referred to together, and “base classes” and “derived classes” are often referred to together.

In C++ inheritance is called derived class, base class hatches except derived class, use: to indicate that the subclass inherits the parent class, C++ supports multiple inheritance, using comma separation

class Parent {
public:
    int name;
protected:
    int code;
private:
    int num;
};

class Parent1 {

};

// in C++, : represents inheritance, which can be separated by commas
/ / public/protected/private inheritance, in the base class has some protection mechanism is private inheritance by default
class Child : public Parent, Parent1 {
    void test(a) {
        // Derived classes can access both public and protected properties
        this->name;
        this->code; }};Copy the code

C++ has added public, protected, and private derivations to its derived classes, and the default is private

Class Derived class name: [inheritance method] base class name {

The newly added member of a derived classCopy the code

};

//private Private inheritance
class Child1 : private Parent {
    void test(a) {
        this->name;
        this->code; }};/ / protected inheritance
class Child2 : protected Parent {
    void test(a) {
        this->name;
        this->code; }};Copy the code

Public, protected, and private derivations limit and protect the properties and methods of the created object that call the parent class

    Child child;
    child.name;/ / public inheritance. The caller has access to the parent public property, but not to the private property

    Child1 child1;
// child1.name; / / private inheritance. The caller does not have access to the parent public and private properties

    Child2 child2;
// child2.name; //protected inheritance. The caller does not have access to the public and private attributes of the parent class
Copy the code

Virtual functions

** key!! ** inheritance in C++ differs from inheritance in Java: base-class member functions and derived member functions do not constitute overloading

Base class members and derived class members of the same name will cause masking, this sentence for the member variable is very good to understand, for the member function to pay attention to, no matter how the function parameter, as long as the same name will cause masking. In other words, base-class member functions and derived member functions do not constitute overloading, and if the derived class has a function with the same name, then all functions in the base class with the same name will be masked, regardless of whether their arguments are the same.

The parent class code is as follows:

class Person {
protected:
    char *str;
public:
    Person(char *str) {
        if(str ! =NULL) {
            this->str = new char[strlen(str) + 1];
            strcpy(this->str, str);
        } else {
            this->str = NULL;
        }
        cout << "parent" << endl;
    }

    Person(const Person &p) {
        cout << "copy parent" << endl;
    }

    void printC(a) {
        cout << "parent printC" << endl;
    }

    ~Person() {
// if (str ! = NULL) {
// delete[] str; // The destructor is called only once if this method is called
/ /}
// cout << "parent destroy" << endl;}};Copy the code

Subclasses inherit from the parent class and call the constructor of the parent class, using: to call the constructor of the parent class

/ / subclass
class CTest : public Person {
public:
    // Call the constructor of the parent class
    CTest(char *str) : Person(str) {
        cout << "child" << endl;
    }

    void printC(a) {
        cout << "child printC" << endl;
    }

    ~CTest() {
        cout << "child destroy "<< endl; }};Copy the code

The difference between C++ and Java is the following code: any pointer to the parent class is the method of the calling parent class. Even if the object of the child class is directly assigned to the parent class, the method of the parent class will be called, but not the method of the child class.

    Person person = CTest("jake");

    person.printC(a);//parent printC

    cout << "-- -- -- -- -- -- -- -- -- -- -" << endl;
    Person *p = NULL;
    CTest c1("123");
    p = &c1;
    c1.printC(a);//child printC
    p->printC(a);//parent printC calls the parent method.
Copy the code

Even through pointer passing and reference passing, any parent class used will call the parent class’s methods

// Only methods of the parent class will be called through the pointer
void howToPaint(Person *p) {
    p->printC(a); }// By referring to a type, only methods of the parent class are called, not methods of the child class
void howToPaint1(Person &p) {
    p.printC(a); } cout <<"-- -- -- -- -- -- -- -- --" << endl;
    howToPaint(p);//parent printC
    howToPaint(&c1);//parent printC

    cout << "-- -- -- -- -- -- --" << endl;
    Person p1("123");
    // are methods of the parent class
    howToPaint1(p1);//parent printC
    howToPaint1(c1);//parent printC

    cout << "-- -- -- -- -- -- -- --" << endl;
    CTest c2("123");
    Person p2 = c2;// Will the parent copy function be called? Copy parent makes the call
Copy the code

Why is that? The memory model is shown in the following figure:

C ++ is called in the order of the function table, so it is obvious that the superclass functions come before the subclass functions

So how do you call a subclass’s method? C ++ provides the means for virtual functions, which are also the key to achieving polymorphism.

Virtual function and pure virtual function, pure virtual function in Java abstract == pure virtual function

In practice, once we define a destructor, we want to use it to clean up the object when it is destroyed, such as freeing memory, closing files, etc. If the class is also a base class, we must declare the destructor virtual, otherwise we risk memory leaks. That is, the destructor of the base class should be declared virtual in most cases.

Classes that contain pure virtual functions are called Abstract classes. It is abstract because it cannot be instantiated, that is, it cannot create objects. For obvious reasons, pure virtual functions have no body, are not complete functions, cannot be called, and cannot be allocated memory.

Abstract classes are usually used as base classes, leaving derived classes to implement pure virtual functions. Derived classes must implement pure virtual functions to be instantiated.

  1. A pure virtual function can make a class an abstract base class, but an abstract base class can contain other member functions (virtual or normal) and member variables in addition to pure virtual functions.
  1. Only virtual functions in a class can be declared as pure virtual functions. Neither ordinary member functions nor top-level functions can be declared as pure virtual functions.
  1. The destructor of the base class must be declared virtual.

#include <iostream>

using namespace std;

class Person {
public:
    // Add a pointer to the virtual table
    virtual void look(a) {// Virtual subclasses can overwrite functions
        cout << "virtual look" << endl;
    }

    virtual void speak(a) {};// Pure virtual functions must be implemented by subclasses
    // The destructor of the base class must be declared virtual
    virtual ~Person() {
        cout << "~Person"<< endl; }};class Child : public Person {
public:
    void speak(a) override {// Subclasses implement pure virtual functions
        cout << "child speak" << endl;
    }

    void look(a) override {
        cout << "child look" << endl;
        Person::look(a);// Access the method of the parent class
    }
    ~Child() {
        cout << "~Child"<< endl; }};int main(a) {
    Person *person = new Child(a);// Abstractions must be derived using Pointers rather than stacks
    person->speak(a);//child speak
    person->look(a);//child look

    Person p;
    cout << sizeof(p) << endl;*vtable *vtable *vtable *vtable *vtable *vtable
    // Use the following code to prove it
    typedef void (*func)(void);
    func fun = NULL;
    cout << (int*)&p << endl;// point to the first address of the function 0x61fdf8
    cout << (int* (*)int*)&p << endl;// Address of the function 0x404560
    fun  = (func)*((int* (*)int*)&p);
    fun(a);//virtual look
    return 0;
}

    /** * child speak child look virtual look ~Child ~Person */
Copy the code

The template

Templates are similar to Java generics. Template classes do not support separate declarations (.h) and implementations (.cpp). The root cause of “you cannot split the declaration and definition of a template into multiple files” is that instantiation of a template is done by the compiler, not the linker, which may result in instances not being found during linking.

  • A function template
#include <iostream>
#include <string>
#include <cstring>

using namespace std;
/** * Function templates are similar to generics in Java

// Method generics can only be declared on methods
template<typename T, typename R=int>
The default type of R is int
//typename == class Two equivalent
void swap2(T t, R r) {
}


template<typename T>
void swapT(T &a, T &b) {
    cout << "swap: T a T b" << endl;
    T temp = a;
    a = b;
    b = temp;
}

// Ordinary functions have higher priority than generic functions, only when the types overlap
void swapT(int &a, int &b) {
    cout << "swap : int a int b" << endl;
    int temp = a;
    a = b;
    b = temp;
}


int main(a) {
    // Function templates
    int a = 10;
    int b = 20;
    char c = 'a';
    swapT<int>(a, b);// Display scheduling
    swapT(a, b);// Automatically derive
// swap(a,c); // The error cannot be derived from the specific type

// swap2(); // The error cannot be derived from the specific type
    return 0;
}


Copy the code
  • Class template
// Template decorates the class
template<typename T, typename R>
class Person {
public:
    T a;
    R b;

    Person(T t) {

    }

    T &getA(a) {
        T t1;
// return t1; // This cannot be returned because the method will be destroyed after execution
        return a;// The return value is reference}};/** * different from Java, more flexible than Java */
class Pp {
public:
    void show(a) {
        cout << "Pp show"<< endl; }};template<typename T>
class ObjTemp {
private:
    T obj;
public:
    void showPp(a) {
        // Check automatically but unexpected errors occur
        obj.show(a);
      
        T is required in Java to call methods
      }};template<typename T, typename R>
class CTest {
public:
    T m_name;
    R m_age;

    CTest(T name, R age) {
        this->m_name = name;
        this->m_age = age;
    }

    void show(a) {
        cout << "show T:" << m_name << " R:"<< m_age << endl; }};template<typename T, typename R>
void doWork(CTest<T, R> &cTest) {
    cTest.show(a); }template<typename T>
void doWork2(T &t) {
    t.show(a);
      
}


// The inheritance template problem is the same as Java
template<typename T>
class Base {
public:
    T t;
};

// Determine the type or template
template<typename T, typename R>
class Son : Base<R> {
public:
    T t1;
};

int main(a){
  	CTest<string, int> test("jake".28);//show T:jake R:28
    doWork(test);
    doWork2<CTest<string, int>>(test);// Display the call
    doWork2(test);// Automatically derive

    ObjTemp<Pp> temp;
    temp.showPp(a);//Pp show can call the methods of the passed template
    
        // Automatic type inference, which cannot be used on class templates to derive specific types
    Person<int, string> p(100);
    cout << p.getA() << endl;
}

Copy the code

ArrayList implements a java-like list of templates:

Note that the.h and.cpp separation we learned earlier does not support templates, and the parts of templates are merged into the.h file.

#include <iostream>

using namespace std;

#ifndef CPPDEMO_ARRAYLIST_H
#define CPPDEMO_ARRAYLIST_H

template<typename T>
class ArrayList {
public:
    int d = 11;

    ArrayList() {
        this->size = 16;
        this->realSize = 0;
        this->arr = new T[this->size];
    }

    // Explicit cannot be called implicitly
    explicit ArrayList(int capacity) {
        this->size = capacity;
        this->realSize = 0;
        // Apply an array in the heap
        this->arr = new T[this->size];// The space created in the heap stores an array of int[size], and arr points to the first address of the array
    }

    // Copy the function
    ArrayList(const ArrayList &arrayList) {
        this->size = arrayList.size;
        this->realSize = arrayList.realSize;
        this->arr = new T[arrayList.size];
        // Assign the array value to the arR
        for (int i = 0; i < this->size; ++i) {
            this->arr[i] = arrayList.arr[i];//arrayList.arr[I] this->arr[I] is a pointer}}// destructor
    ~ArrayList() {
        if (this->arr ! =nullptr) {
            delete[] this->arr;
            this->arr = nullptr; }}void add(T val) {
        add(val, this->realSize);
    }

    void add(T val, int index) {
        if (index < 0 || index > size) {
            return;
        }
        // Determine whether the capacity is large enough for expansion
        if (this->realSize >= size * 0.75) {
            resize(a); }this->arr[index] = val;// equivalent to *((this->arr)+index) = val
        this->realSize++;// Data size +1
    }

    T get(int index) {
        if (index < 0 || index >= realSize) {
            return - 1;
        }
        return this->arr[index];
    }

    T remove(int index) {
        if (index < 0 || index >= realSize) {
            return - 1;
        }
        // How to remove it? Cycle forward
        int result = this->arr[index];
        for (int i = index; i < size - 1; ++i) {
            this->arr[i] = this->arr[i + 1];
        }
        this->realSize--;
        // Determine the capacity reduction
        return result;
    }

    //const is defined as constant
    int getLength(a) const {
        // realSize = realSize - 1; You can't modify all the variables inside the function
        c = 11;// Mutable variables can be modified in constant functions
        return realSize;
    }

    bool isEmpty(a) const {
        return realSize == 0;
    }

    void resize(a) {
        int netLength = size * 2;
        T *p = new T[netLength];
        // Copy data
        for (int i = 0; i < size; ++i) {
            *(p + i) = this->arr[i];
        }
        // Free the previous array
        delete[] this->arr;
        // reassign
        this->arr = p;
        this->size = netLength;
    }

    void toString(a) {
        cout << "[";
        for (int i = 0; i < realSize; ++i) {
            cout << arr[i] << ",";
        }
        cout << "]" << endl;
    }

private:
    int size{};// Size of the container
    int realSize{};// The true array length
    T *arr;// We cannot use arrays here because array names are arR pointer constants and cannot be reassigned to arr. Pointers are pointer variables and array names are just pointer constants
    mutable int c = 10;// Variables that can be modified in a mutable function need to be modified using mutable
};


#endif //CPPDEMO_ARRAYLIST_H

Copy the code

string

    // String is unique to C++. String is an object that encapsulates the same string representation as C
    string s1(a);
    string s2("123");
    string s3 = "wew";//string string is declared in the heap
    string s4(4.'k');//4 K's constitute KKKK
    string s5("123456".1.4);// Output four strings starting from 1:2345
    cout << s4 << "" << s5 << endl;
    s2.append(s3);/ / an extra 123 wew
    s2.append(s3,1.2);//ew
    cout << s2 << endl;//123wewew
    string sub = s2.substr(2.3);// String clipping
    cout << sub << endl;//3we

    s4.swap(s5);// String swaps. Only references and addresses change external values

    //c_str supports C and is converted to char *
    string s = "jakeprim";// The destructor is removed from the heap after the method is executed
    // This is not the case
    const char *s_c = s.c_str(a);// Convert a C++ string to a C - enabled string, return a constant pointer
    printf("%s\n", s_c);

    FFmpeg uses C, so C conversion is necessary when using C++ development
    char ss[20];
    strcpy(ss, s.c_str());// Copy to a new variable
Copy the code