类的继承:
通过继承来减少代码量与提高复用性,一个基本例子:
class Father {
public:
    int age;
    string name;
    
    Father(): age(30),name("Father") {}
}
class Son: public Father {
public:
    int examScore;
    
    Son(): examScore(100) { // 不可以在这里初始化age和name
        // 值得注意的是,继承来的成员属性只能在方法内更改,不可以使用初始化列表更改。
        age = 10;
        name = "Son";
    }
}访问权限:
可以用来控制成员变量与函数能否被访问,有private、protected和public三种。其访问权限如下:

继承类型:
我们一般就用public来继承,但不排除特殊情况,也是有private、protected和public三种,其继承含义如下:
① 公有继承(public):父类的public和protected成员都成为了子类的public和protected成员,但父类的private成员不能直接访问,可以通过public或protected的方法来访问或修改。
② 保护继承(protected):父类的public和protected成员都变成了子类的protected成员。
③ 私有继承(private):父类的public和protected成员都成为了子类的private成员。
class Father {
public:
    int a;
protected:
    int b;
private:
    int c;
};
class Son1 : public Father { // public继承
public:
    void show() {
        cout << a << endl; // 可以输出
        cout << b << endl; // 可以输出
        cout << c << endl; // 报错,因为父类的c是private的
    }
};
class Son2 : protected Father { // protected继承
public:
    void show() {
        cout << a << endl; // 可以输出
        cout << b << endl; // 可以输出
        cout << c << endl; // 报错,因为父类的c是private的
    }
};
class Son3 : private Father { // private继承
public:
    void show() {
        cout << a << endl; // 可以输出
        cout << b << endl; // 可以输出
        cout << c << endl; // 报错,因为父类的c是private的
    }
};
class GrandSon : public Son3 { //public继承,但父类是Son3
public:
    void show() {
        // 三个输出都报错,因为Son3里继承的abc都变成了private的了
        cout << a << endl;
        cout << b << endl;
        cout << c << endl;
    }
};
int main() {
    // Father f;
    // cout << f.a << endl; // 可以输出
    // cout << f.b << endl; // 报错,protected的
    // cout << f.c << endl; // 报错,private的
    // Son1 s1;
    // cout << s1.a << endl; // 可以输出
    // cout << s1.b << endl; // 报错,protected的
    // cout << s1.c << endl; // 报错,private的
    // s1.show();
    // Son2 s2;
    // cout << s2.a << endl; // 报错,protected的
    // cout << s2.b << endl; // 报错,protected的
    // cout << s2.c << endl; // 报错,没有继承这个成员
    // s2.show(); 
    //Son3 s3;
    //cout << s3.a << endl; // 报错,private的
    //cout << s3.b << endl; // 报错,private的
    //cout << s3.c << endl; // 报错,没有继承这个成员
    // s3.show();
    return 0;
}子类的初始化:
当一个子类被初始化的时候,会先初始化它的父类,然后再初始化子类。
当一个子类被销毁的时候,会先销毁子类,再销毁它的父类。
class Father {
public:
    Father() {
        cout << "Father()" << endl;
    }
    ~Father() {
        cout << "~Father()" << endl;
    }
};
class Son : public Father {
public:
    Son() {
        cout << "Son()" << endl;
    }
    ~Son() {
        cout << "~Son()" << endl;
    }
};
int main {
    Son s;
    return 0;
}上述程序的输出为:
Father()
Son() 
~Son()
~Father()有一种类似的情况,就是当一个类的成员变量是另一个类的实例对象时,也是先初始化这个成员变量所在的类,再初始化这个类本身:
class Father {
public:
    Father() {
        cout << "Father()" << endl;
    }
    ~Father() {
        cout << "~Father()" << endl;
    }
};
class Son{ // 注意看,这个类没有继承
public:
    Father s; // 但是他有一个Father的对象作为成员
    Son() {
        cout << "Son()" << endl;
    }
    ~Son() {
        cout << "~Son()" << endl;
    }
};
int main() {
    Son s;
    return 0;
}上述程序输出为:
Father()
Son()
~Son()
~Father()子类与父类的冲突:
如果子类和父类定义了一个同名的成员,那么会优先调用子类的:
class Father {
public:
    char dream;
    Father() : dream('b') {}
};
class Son : public Father {
public:
    char dream;
    Son() : dream('c') {}
};
int main() {
    Son s;
    cout << s.dream << endl; //输出的是c而不是b。
    cout << s.Father::dream << endl; //这样就可以访问父类的dream了,输出的是b
}同理,如果子类和父类有一个同名的函数,会优先执行子类的。但值得注意的是,如果父类里面存在函数的重载,那么如果子类重写了父类的某一个函数,那么就没有办法继承来自父类的原来的重载的函数,如果子类没有重写任何一个父类的包含重载的函数,那么子类将能继承父类所有的重载函数。(别看了,太tm绕了。。。
多继承:
一个子类可以有多个父类(但人不行啊),多继承不太常用,仅举个例子:
class Father {
public:
    int height;
    int age;
};
class Mother {
public:
    int beauty;
    int age;
};
class Son : public Father, public Mother {
};
void main() {
    Son s;
    cout << s.age << endl; // 报错,因为同时继承了两个age,下面的菱形继承会解决这种情况
    cout << s.Father::age << endl; // 正常输出
    cout << s.Mother::age << endl; // 正常输出
    cout << s.height << endl;// 正常输出
    cout << s.beauty << endl;// 正常输出
}菱形(钻石)继承:
菱形继承也是子类和父类的一种冲突,比如如下情况:
class Animal {
public:
    int age;
};
class Yang: public Animal {};
class Tuo: public Animal {};
class YangTuo: public Yang, public Tuo {};可以看到,羊驼继承了羊和驼,但是,羊和驼都继承了动物,也就是说,羊驼有两个age了,这是不应该的,产生了冲突。因此,我们需要使用虚拟继承来解决这个问题:
class Animal {
public:
    int age;
};
class Yang: virtual public Animal {}; // 虚拟继承
class Tuo: virtual public Animal {}; // 虚拟继承
class YangTuo: public Yang, public Tuo {};
int main() {
    YangTuo s;
    s.age = 18;
    s.Yang::age = 28;
    s.Tuo::age = 38;
    cout << s.age << endl; // 输出38
    cout << s.Yang::age << endl; // 输出38
    cout << s.Tuo::age << endl; // 输出38
    return 0;
}通过虚拟继承,可以解决上述问题,但奇怪的是,上面的程序的三个输出都是38,也就是,这三个age指向的是同一个变量!C++为了解决菱形继承的问题,特别引入了这么一种特殊的机制,如果存在菱形继承的错误,那么就会使用一个类似指针的东西,去保存这个冲突的变量,然后让冲突的子类和父类都共享这个指针。
子类继承父类后占用空间:
按照直觉去想,因为子类没办法继承父类的private成员,那么应该不会因为父类的private成员而消耗内存,实际上不是这样的:
class Father {
public:
    int id;
protected:
    int age;
private:
    int bank_card;
};
class Son : public Father {
public:
    int n_toy;
};
int main() {
    Father f;
    Son s;
    cout << sizeof(f) << endl; // 输出12,三个int,每个int占4字节
    cout << sizeof(s) << endl; // 输出16,说明父类的private成员也被继承下来了!
    return 0;
}原因其实很简单,因为其实子类是可以通过调用父类的public或protected方法来访问父类的private变量的,所以也要把父类的private继承下来,但只是不能直接访问罢了。
当然,其实没那么简单,上述例子只讨论了全部成员都是同一个类型的情况,如果类型不同,那么就涉及到内存对齐的问题了,但这个问题非常复杂,这里不做讨论。
 
          
        