多态、虚函数、虚函数表

C++.png

多态

  • 默认情况下,编译器只会根据指针类型调用对应的函数,不存在多态

  • 多态是面向对象非常重要的一个特性

    • 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
    • 在运行时,可以识别出真正的对象类型,调用对应子类中的函数
  • 多态的要素

    • 子类重写父类的成员函数(override)
    • 父类指针指向子类对象
    • 利用父类指针调用重写的成员函数

虚函数

  • C++中的多态通过虚函数(virtual function)来实现
  • 虚函数:被virtual修饰的成员函数
  • 只要在父类中声明为虚函数,子类中重写的函数也自动变成虚函数(也就是说子类中可以省略virtual关键字)

虚表

虚函数的实现原理是虚表,这个虚表里面存储着最终需要调用的虚函数地址,这个虚表也叫虚函数表


struct Animal {
    int m_age;
    virtual void speak(){
        cout << "Animal::speak()" << endl;
    }
    virtual void run(){
        cout << "Animal::run()" << endl;
    }
};

struct Cat:  Animal {
    int m_life;
    virtual void speak(){
        cout << "Cat::speak()" << endl;
    }
    virtual void run(){
        cout << "Cat::run()" << endl;
    }
};

int main() {
    Animal *cat =new Cat();
    cat->speak();
    cat->run();
    
    return 0;
}
// log:
Cat::speak()
Cat::run()

注意,一定要指针,如果是对象,就失灵了。多态的三要素缺一不可。

int main() {
    Animal cat = Cat();
    cat.speak();
    cat.run();
    
    return 0;
}
// log:
Animal::speak()
Animal::run()

虚表(x86环境的图)

调用父类的成员函数实现

class Animal {
public:
    virtual void speak(){
        cout << "Animal::speak()" << endl;
    }
};

class Cat: public Animal {
public:
     void speak(){
        Animal::speak();
        cout << "Cat::speak()" << endl;
    }
};

int main() {
    Animal cat = Cat();
    cat.speak();
    
    return 0;
}
// log:
Animal::speak()

Q:为啥不继续执行下面的代码
A:上面不是多态

int main() {
    Animal *cat = new Cat();
    cat->speak();
    
    return 0;
}
// log:
Animal::speak()
Cat::speak()

虚析构函数

  • 含有虚函数的类,应该将析构函数声明为虚函数(虚析构函数)
  • delete父类指针时,才会调用子类的析构函数,保证析构的完整性
class Animal {
public:
    virtual void speak(){
        cout << "Animal::speak()" << endl;
    }
    virtual ~Animal(){
        cout << "Animal::~Animal()" << endl;
    }
};

class Cat: public Animal {
public:
     void speak(){
        Animal::speak();
        cout << "Cat::speak()" << endl;
    }
    
    ~Cat(){
        cout << "Animal::~Cat()" << endl;
    }
};

int main() {
    Animal *cat = new Cat();
    cat->speak();
    
    return 0;
}

// log:
Animal::speak()
Cat::speak()

Q:为啥不析构

你可能感兴趣的:(多态、虚函数、虚函数表)