c++第六天(多态)

一般来说,在其他语言中,多态就是父类指针指向了子类对象
但是对于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;

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值