c++第六天(多态)

    xiaoxiao2025-01-12  20

    一般来说,在其他语言中,多态就是父类指针指向了子类对象 但是对于c++来说,对象不一定是在堆区,还有可能在栈区,那么这时候的多态会是什么样的呢?

    多态和虚函数

    c++中的多态分为 静态多态 和 动态多态 静态多态:实质上就是函数重载 一般说的多态实质上指的是 动态多态

    先来看一个例子

    class Father{ public: void who(){ cout << "father" << endl; } }; class Son:public Father{ void who(){ cout << "son" << endl; } }; void say(Father& obj){ obj.who(); } int main(int argc, const char * argv[]) { Son son; say(son); }

    输出为:father 因为普通成员函数的调用和全局函数实质上没有上面区别,在编译的时候就已经决定调用Fahter的say函数,称之为静态绑定。 如果想要输出为:son,就要使用动态绑定,将who声明为 virtual

    class Father{ public: virtual void who(){ cout << "father" << endl; } }; class Son:public Father{ public: void who(){ cout << "son" << endl; } }; void say(Father& obj){ obj.who(); } int main(int argc, const char * argv[]) { Son son; say(son); }

    为什么会出现这样的情况呢?

    如果who没有加virtual,Father对象的内存大小为1个字节。如果加了virtual,Father对象的大小变为4个字节,因为对象内部多了一个 vfptr 指针,指向该类对应的虚函数表。Son继承于Father,因此也继承了父类的 vfptr 指针和虚函数表,由于是继承的父类的vfptr,所以一开始子类的vfptr指向的是父类的虚函数表(指针内容相同),但在对象的构造函数中,会将vfptr指向子类自己的虚函数表。如果没有重写父类的 say 函数,子类虚函数表中say和父类虚函数表中的say是一样的。如果重写了父类的say函数,就会用重写的say函数替换虚函数表中的say函数。

    虚函数表是动态联编的,运行的时候,才会通过虚函数指针找到虚函数表中对应的函数。

    抽象类和纯虚函数

    class Father{ //这样声明了一个纯虚函数,也就是只有函数声明,没有函数实现的函数 //一旦一个类中有纯虚函数,这个类就不能被实例化,这种类就是c++中的抽象类 virtual void func() = 0; } class Son:Father{ //子类继承了抽象类,就必须实现抽象类的纯虚函数 virtual void func(){ return 0; } }

    虚析构和纯虚析构函数

    虚析构函数用于解决多态时,子类释放不干净的情况 在使用多态的时候,由于使用了父类指针指向了子类对象,因此在调用析构函数的时候,只会调用父类的析构函数。这个时候就需要将析构函数转化为虚函数。

    class Father{ virtual ~Father(){}; } class Child{ ~Child(){}; } int main(){ Father* c = new Child; // 多态 delete c; // 因为Father的析构函数是虚函数,因此c释放的时候会同时调用子类和父类的析构函数 }

    纯虚析构函数 类内声明,类外实现加粗样式

    class Father{ virtual ~Father(){} = 0; } Father::~Father(){};

    有纯虚析构函数的类,也是虚类,因此不能实例化。

    析构函数和纯虚析构函数其实差不多,都要实现,只是一个在类内,一个在类外,另外,有纯虚析构函数的类是虚类,不能被实例化。

    向上类型转换和向下类型转换

    将子类指针或引用转化为父类是安全的

    Son* s = new Son; Father* f = (Father*)s;

    因为父类指针的寻址范围总是小于子类(多态就是这种情况) 但是反过来就不安全了 不安全

    Father* f = new Father; Son* s = (Father*)f;

    如果将父类指针强转为子类,子类指针的寻址范围会超出父类的范围

    最新回复(0)