【C++学习日记】8.3 8.4 8.7

8.3虚函数

如果需要通过基类的指针指向派生类的对象,并且访问访问某个和基类同名的成员,就需要在基类中将同名函数声明为虚函数。从而实现多态。

1.一般虚函数成员

语法形式:

virtual 函数类型 函数名(形参表);

1.虚函数声明只能出现在类定义中的函数原型声明中

2.派生类中的虚函数会隐藏基类中同名函数的所有重载形式

EG 8-4

#include <iostream>
using namespace std;
class base1
{
    public:
    virtual void show(){cout<<"base1 is constructing"<<endl;}
};
class base2:public base1
{
    public:
    virtual void show(){cout<<"base2 is constructing"<<endl;} //可以在派生类中同样用virtual来提醒自己这是个虚函数
};
void fun(base1* ptr) //必须是指针或者引用才可以发挥虚函数的作用
{
    ptr->show(); //如若改成 ptr->base2::show(),则无论ptr指向的类是什么,都会调用base2的show函数
}

int main()
{
    base1 b1;
    base2 b2;
    fun(&b1);
    fun(&b2);
    return 0;
}

运行结果

base1 is constructing
base2 is constructing

2.虚析构函数

如果有可能通过基类指针调用对象的析构函数(通过delete),就需要让基类的析构函数成为虚函数。

EG 8-5

#include <iostream>
using namespace std;
class base
{
    public:
    virtual ~base(){cout<<"desructing base"<<endl;}
};
class derived:public base
{
    public:
    derived(){p=new int(0);}//动态分配内存,结束调用后必须用delete删除内存
    virtual ~derived(){cout<<"destructing derived"<<endl;}
    private:
    int *p;
};
void fun(base *ptr)
{
    delete ptr;
}
int main()
{
    base *b=new derived();//调用默认构造函数生成1个derived类的对象,将其地址赋给b
    fun(b);
    return 0;
}

运行结果

destructing derived//根据7.4,先调用派生类析构函数,再调用基类析构函数
desructing base

8.4纯虚函数与抽象类

1.纯虚函数

声明格式:

virtual 函数类型 函数名(参数表)=0;

声明为纯虚函数后,基类中可以不再给出函数的实现部分

注意:纯虚函数≠函数体为空的虚函数!

2.抽象类

带有纯虚函数的类是抽象类。抽象类不能实例化,即不能定义一个抽象类的对象,只能定义其指针和引用。

EG 8-6

#include <iostream>
using namespace std;
class base1
{
    public:
    virtual void show() =0;//纯虚函数定义
};
class base2:public base1
{
    public:
    void show(){cout<<"base2 is constructing"<<endl;} 
};
class derived:public base2
{
    public:
    void show(){cout<<"derived is constructing"<<endl;}
};
void fun(base1* ptr) 
{
    ptr->show(); 
}

int main()
{
    base2 b2;
    derived d1;
    fun(&b2);
    fun(&d1);
    return 0;
}

运行结果

base2 is constructing
derived is constructing

8.7 多态

多态类型是指有虚函数的类类型。多态类型的析构函数建议使用虚函数。

1.运行时类型识别

1.dynamic_cast

dynamic_cast可以将基类指针显式转换为派生类指针,并且会在转换前检查指针所指向对象的类型与转换的目的类型是否兼容,若兼容则进行转换,不兼容则会得到一个空指针。且转换前类型必须是是指向多态类型的指针。

Explanation


#include <iostream>
#include <assert.h>//assert断言的头文件
 
using namespace std;
 
// 我是父类
class Tfather
{
public:
	virtual void f() { cout << "father's f()" << endl; }
};
 
// 我是子类
class Tson : public Tfather
{
public:
	void f() { cout << "son's f()" << endl; }
 
	int data; // 我是子类独有成员
};
 
int main()
{ 
	Tfather father;
	Tson son;
	son.data = 123;
 
	Tfather *pf;
	Tson *ps;
	//子到父
	/* 上行转换:没有问题,多态有效(参考7中类型兼容规则) */
	ps = &son;
	pf = dynamic_cast<Tfather *>(ps);
	pf->f();
 //子到子
	/* 下行转换(pf实际指向子类对象):没有问题 */
	pf = &son;
	ps = dynamic_cast<Tson *>(pf);
	ps->f();
	cout << ps->data << endl;		// 访问子类独有成员有效
 //父到子,因为子类新增了成员,所以会失败,返回一个空指针
	/* 下行转换(pf实际指向父类对象):含有不安全操作,dynamic_cast发挥作用返回NULL */
	pf = &father;
	ps = dynamic_cast<Tson *>(pf);
	assert(ps != NULL);			 	// 违背断言,阻止以下不安全操作
	ps->f();
	cout << ps->data << endl;		// 不安全操作,对象实例根本没有data成员
	return 0;
}

运行结果

son's f()
son's f()
123
  
Assertion failed: (ps != NULL), function main, file tempCodeRunnerFile.cpp, line 46.
zsh: abort      "/var/folders/45/m9lm0lfj5zj133tbhrqfqb_80000gn/T/"tempCodeRunnerFile

1.assert()函数

若括号内表达式值为1(条件成立),assert不执行任何操作;

若括号内表达式值为0(条件不成立),assert函数会打印一条错误信息,并中止程序。

2.基类到派生类的显式转换

若派生类新增了成员,便会转换失败。

2.typeid

typeid用于获取一个类型的相关信息,通过typeid得到一个type_info类型的常引用

语法形式:

typeid(表达式) 或 typeid(类型说明符)

EG 8-10

#include <iostream>
#include <typeinfo>
using namespace std;
class base
{
    public:
    virtual ~base(){}
};
class derived:public base
{

};
void fun(base *b)
{
    const type_info &info1=typeid(b);
    const type_info &info2=typeid(*b);
    cout<<"typeid(b):"<<info1.name()<<endl;
    cout<<"typeid(*b):"<<info2.name()<<endl;
    if(info2==typeid(base)) cout<<"This is a base class!"<<endl;
}
int main()
{
    base b;
    fun(&b);
    derived c;
    fun(&c);
    return 0;
}

运行结果

typeid(b):P4base
typeid(*b):4base
This is a base class!
typeid(b):P4base
typeid(*b):7derived
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值