C++学习三--多态、异常、转换函数、模板


一、多态

派生类 重写 原类的功能

示例:

class A   //原类
{
	show()
	{
		cout<<~~~~~A”;
	}
};
Class B:public A  //派生类
{
	show()   //重写函数
	{
		cout<<~~~~~~B”;
	}
};

A a;
B b;
a.show();
b.show();

使用时,a.show()显示~~~~~A, b.show()显示~~~~~~B,也就是派生类 重写的show 覆盖 原类的show

正常的情况就是 重写的功能 覆盖 原功能,但是加入指针就会出现问题,因为C++中允许原类的指针 指向 派生类的地址。

看下面实例代码:

#include <iostream>

using namespace std;

class A
{
public:
	void show()
	{
		cout << "AAAAAAAAAA" << endl;
	}
};
class B:public A
{
public:
	void show()
	{
		cout << "BBBBBBBBBB" << endl;
	}
};

int main()
{
	B b;
	A *a = &b;  //原类指针 获取 派生类地址

	a->show();  

	return 0;
}

打印结果为:
在这里插入图片描述
可以看出明明是派生类对象,因为原类指针的问题,打印出原类的功能函数。


  1、虚函数

为解决上述多态问题,引入C++引入虚函数,具体就是在原类功能前面加入virtual关键字就行了

将上述的实例代码改为

#include <iostream>

using namespace std;

class A
{
public:
	virtual void show()
	{
		cout << "AAAAAAAAAA" << endl;
	}
};
class B:public A
{
public:
	void show()
	{
		cout << "BBBBBBBBBB" << endl;
	}
};

int main()
{
	B b;
	A *a = &b;

	a->show();

	return 0;
}

打印结果为:
在这里插入图片描述
打印正常。


  2、纯虚函数

形式类似于:virtual void func() = 0;,即不写实现过程,让函数等于0。

作用:常作为接口,功能实现交给派生类实现。


  3、虚析构函数

析构函数前加virtual关键字,落实到问题上其实还是还是指针的问题,具体看实例代码

实例代码:

#include <iostream>

using namespace std;

class A
{
public:
	~A()
	{
		cout << "AAAAAAAAAA" << endl;
	}
};
class B:public A
{
public:
	~B()
	{
		cout << "BBBBBBBBBB" << endl;
	}
};

int main()
{
	A *a = new B;  
	delete a;

	return 0;
}

打印结果:
在这里插入图片描述
可以看出只执行了原类的析构函数,派生类的析构函数没有执行,这样有时候会导致内存不完全释放的问题。

加上virtual后的打印结果:
在这里插入图片描述


二、异常

C语言中,我们经常通过判断函数的返回值,来判断程序是否出错。但这样会出现一种情况,就是当函数求出的返回值函数出错时的返回值一样时,我们不知道是程序是否出错。
C++使用异常来升级程序执行错误的处理,使用方法看下面的示例代码。

示例代码:

#include <iostream>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

int myatoi(const char *str)
{
	if(*str<'0' || *str>'9') //转化的字符串第一个字符不是数字时
		throw "wrong arg!!!!";  //抛出错误,字符串为主函数中的p
	else
		return atoi(str);
}

int main()
{
	try  //程序没有出错时
	{
		int data = myatoi("asdfas");

		cout<< data <<endl;
	}
	catch(const char *p)  //程序出错时的处理
	{
		cout << p << endl; //打印抛出的错误
	}
}

  1、exception类

C++标准库给出的异常处理类,我们使用其派生类来进行异常处理,具体以下面的示例代码所示。

示例代码:

#include <iostream>
#include <stdlib.h>
#include <exception>

using namespace std;

class myexception:public exception  //使用exception派生类
{
public:
	const char *what() const throw()  
	{
		return "aaaaaa";  //出错处理自定义
	}
};

int myatoi(const char *str)
{
	if(*str < '0' || *str > '9')
		throw myexception();  //抛出错误
	else
		return atoi(str);
}

int main()
{
	int a;

	try  //程序没有出错时
	{
		a = myatoi("adada");
	}
	catch(myexception e)  //异常处理
	{
		cout << e.what() << endl;  //打印出错信息
	}
	return 0;
}

使用时,一定记得要加头文件


  2、预定义异常类

标准库包含的异常处理类

在这里插入图片描述


三、转换函数

对象之间的类型转换

  1、标准转换函数

  • reinterpret_cast
    • reinterpret_cast<new type>(expression)
      将一个类型的指针转换为另一个类型的指针,它也允许从一个指针转换为整数类型
  • const_cast
    • const_cast< new type>( expression)
      const指针与普通指针间的相互转换,注意:不能将非常量指针变量转换为普通变量
  • static_cast
    • static_cast<new type>(expression)
      主要用于基本类型间的相互转换,和具有继承关系间的类型转换
  • dynamic_cast
    • dynamic_cast<newtype>(expression)
      只有类中含有虚函数才能用dynamic_cast;仅能在继承类对象间转换
      dynamic_cast具有类型检查的功能,比static_cast更安全

  2、自定义转换函数

自定义转换类型的实现,一般形式为:operator 类型(){ 实现步骤}

示例代码:(包含标准转化函数)

#include <iostream>
#include <exception>
using namespace std;

class A
{
public:
	virtual void show()
	{
		cout << "xxxxxxx" << endl;
	}
	operator int()  //重定义int类型的强转
	{
		return 10;
	}
};
class B:public A
{
	void show()
	{
		cout << "aaaaaaa" << endl;
	}
};

int main()
{

#if 0
	int a;

	char *P = reinterpret_cast<char *>(&a);

	return 0;
#endif
#if 0
	const int b = 100;

	int *p = const_cast<int *>(&b);
#endif
#if 0
	A a;
	B &p = static_cast<B &>(a);
#endif
#if 0
	try{
		A a;
		B &p = dynamic_cast<B &>(a);
	}
	catch(bad_cast e)
	{
		cout << e.what() << endl;
	}
#endif
	A a;
	int t = a;  //对象a自动转化为int类型,并调用int转换函数

	cout << a << endl;
}

  3、隐式转换 – explicit

示例:

#include <iostream>

using namespace std;

class mempool
{
public:
	explicit mempool(int size)
	{
		data = new char[size];	
		cout<< "cccccccccc" <<endl;
	}
	~mempool()
	{
		delete [] data;
	}

private:
	char *data;
};

int main()
{
//	mempool a(100);
	mempool a = 100;
}

四、模板

  1、类型模板

类似于C语言中的typedefdefine功能
使用形式为:template < typename T>

使用实例:

#include <stdio.h>
#include <iostream>

using namespace std;

template<typename XXX>
XXX add(XXX a, XXX b)
{
	return a+b;
}

int main()
{
	cout<< add(1, 2) <<endl;  //自动转化为int类型相加
	cout<< add(1.1, 2.3) <<endl;  //自动转化为double类型相加
}

  2、模板特化

模板类的特殊情况

示例代码:

#include <stdio.h>
#include <iostream>

using namespace std;

#if 0
int add(int a, int b)
{
	return a+b;
}

double add(double a, double b)
{
	return a+b;
}
#endif

template<typename XXX>
XXX add(XXX a, XXX b)
{
	return a+b;
}

template <>   //上面模板内容的特殊情况,这里自定义处理
bool add(bool a, bool b)
{
	if(a == true && b == true)
		return true;
	return false;
}

int main()
{
	cout<< add(1, 2) <<endl;
	cout<< add(1.1, 2.3) <<endl;
	cout<< add(true, false) <<endl;
	cout<< add(true, true) <<endl;
}

在这里插入图片描述

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

修成真

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值