C++回顾之面向对象程序设计

  1. 核心思想:数据抽象,继承和动态绑定(一定程度上忽略类型的区别)。

  2. 虚函数:基类希望它的派生类各自定义适合自己的版本,则将函数声明为虚函数。函数声明前加上virtual

  3. 派生类中实现虚函数时在函数声明尾加上override,前面可以加上virtual也可以不加。一旦某个函数被声明成虚函数,则在所有派生类中它都是虚函数。

  4. protected:派生类有权访问该成员,但是禁止其他用户访问。

  5. 虚函数的解析过程在运行时,派生类如果没有重写虚函数则使用基类的。

  6. 派生类对象的构造函数:首先初始化基类的部分,然后按照声明的顺序依次初始化派生类的成员。

  7. 基类的静态成员无论派生出多少个类都只有一个唯一实例。

  8. 使用final 使得一个类是不可以继承的。把基类的函数声明为final,则子类不可以重写该函数。

  9. 静态类型:编译时已知。动态类型:变量表示的内存中的对象的类型,运行时才可知。

  10. 如果虚函数使用默认实参,则基类和派生类中定义的默认实参最好一致,如果某次函数调用使用了默认实参,则该实参值由本次调用的静态类型决定。

  11. 回避虚函数的机制

        double a = base->Quote::net_price(33); //强行调用基类版本,而不管base的类型是什么
    
  12. 纯虚函数:函数声明后面加上=0,有纯虚函数的类是抽象基类。

  13. protected:派生类的成员或友元只能通过派生类对象来访问基类的受保护对象。派生类对于一个基类对象中的受保护成员没有任何访问特权(例如成员函数接受一个基类对象的指针,但不可以直接通过指针访问protected成员数据)。公有继承其实就是继承了基类的公有接口和protected成员(基类的public为子类的public,可以直接被子类对象调用。基类的protected为子类的protected,只能子类内部用),private子类是不可以直接用的。

    
    #include <iostream>
    
    
    #include <memory>
    
    
    #include <string>
    
    using namespace std;
    class A {
    private:
        int a;
        int b;
    protected:
        int c;
    public:
        int d;
    };
    class B :public A {
    public:
        void f(B & b) {
            b.c = 5; // 对的,在自己成员函数内部
            b.d = 6;
            //b.a = 1; 这句话是错误的,私有成员
        }
        void ff(A & a) {
            a.d = 7;
            //a.c = 6; 这也是错误的!
        }
    };
    
    int main() {
        B b;
        b.d = 6;
        //b.c = 6;错的
    }
  14. 私有继承:子类继承来的东西都是子类的private(基类的public和protected成了子类的private),子类的子类就无法使用这些基类东西了(相当于对子类的子类来说,继承的东西都是父类的private)。

  15. 保护继承:子类继承来的东西都是子类的protected(基类的public和protected成了子类的prote),子类的子类成员函数可以使用这些东西,但是不可以通过子类的子类对象直接调用原来是public的东西了。

  16. 友元关系不可以继承。基类声明另一个类为友元。则另一个类可以访问基类成员以及基类派生类的基类成员部分。

  17. 改变子类个别成员的可访问性:

    public :
    using Base::size; //将子类继承来的size函数变为public的
  18. 名字查找优于类型检查:子类重载父类函数,则父类函数永远被隐藏。这也是子类虚函数要与基类虚函数有相同的形参列表的原因。否则基类指针接受子类对象,调用的函数只能是基类的函数,因为从子类的角度看,并没有重写虚函数,而是定义了一个新函数。

    
    #include <iostream>
    
    using namespace std;
    class A {
    public:
        virtual void f(int a = 6) { cout << "base" << a; }
    };
    class B :public A {
    public:
        void f(int a = 7) { cout << "Nobase" << a; }
    };
    void text(A * p) {
        p->f();
    }
    int main() {
        B temp;
        text(&temp);
        int a;
        cin >> a;
        return 0;
    }
    //输出结果:Nobase6
    //将基类函数的参数去掉:base
  19. 成员函数不管是否是虚函数都可以被重载。派生类要重载一个基类函数版本,则需要重载同个函数的所有版本。可以通过using声明直接使用基类的各个版本,而只是改变其中一个。如果不通过虚函数而直接重载基类函数,那么将子类传给基类指针,通过基类指针访问到的是基类版本的函数。

  20. 因此,应该给基类一个虚析构函数。析构函数体自身并不直接销毁成员(在析构函数体执行完毕后,成员会被自动销毁)。当我们delete一个动态分配的对象的指针时将执行析构函数。将虚构函数定义为虚,这样子在使用基类指针delete一个子类对象时才可以找到正确的子类虚构函数。

  21. 派生类的赋值运算符必须显示为其基类部分赋值,或者在函数内直接调用基类相应函数:

Base::operator=(rhs) // 基类的赋值运算符是默认的,也可以使用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值