C++ 多态

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、多态的引入

有这么一种场景,派生类覆写(函数名,参数,返回值都一样,只是函数实现体不一样)了父类的某函数func,外部有个入参为父类对象的函数 test_func,想通过这个test_func分别传入父类和派生类的对象时分别调用父类和派生类各自对func的实现。

//派生类覆写了基类的函数func;
Base b;
Sub  s;
void test_func(Base &b) { b.func(); } 
test_func(b); // 调用Base的func 
test_func(s); // 想调用Sub的func怎么办?

上面的例子中,如果对Base和Sub类的func方法不做特殊处理的话,test_func(s);还是调用Base的func,这不是我们想要的。

人类用手吃饭是本能;
英国人用刀叉吃饭;
中国人用筷子吃饭;
我们问“这个人怎么吃饭的?”,
应该根据其国别来回答,而不是简单地说“用手吃”。
这就是多态。

func是一般的函数时,无法达到上述目的,需要在func的声明加上virtual前缀设置为虚函数才可以。

原理:1) 对于虚函数,采用动态联编:有虚函数的对象里有一个指针,指向虚函数表;调用虚函数时,会根据对象里的指针找到表,从表中取出函数来执行。2) 对于非虚函数,采用静态联编:编译时就确定调用哪个函数。3) 差别:静态联编效率高,动态联编支持多态

二、多态的限制

  1. 传对象的指针或引用才有多态,传值无多态。
test_func(Human* h):
test_func(Human& h)// 使用指针或引用来使用对象时,才有多态
test_func(Human h)// 传值时,无多态
  1. 只有类的成员函数才能声明为虚函数
  2. 静态成员函数不能是虚函数
  3. 内联函数不能是虚函数
  4. 构造函数不能是虚函数 (实例化对象时需要构造函数立刻被调用,是来不及等到运行时再做的。TBD:待学习补充更详细的解释)
  5. 析构函数一般都声明为虚函数
#include <iostream>
#include <string.h>
#include <unistd.h>

using namespace std;

class Human {
private:
	int a;
public:
	virtual void eating(void) { cout<<"use hand to eat"<<endl; }
	virtual ~Human() { cout<<"~Human()"<<endl; }
};

class Englishman : public Human {
public:
	void eating(void) { cout<<"use knife to eat"<<endl; }
	virtual ~Englishman() { cout<<"~Englishman()"<<endl; }
};

class Chinese : public Human {
public:
	void eating(void) { cout<<"use chopsticks to eat"<<endl; }
	virtual ~Chinese() { cout<<"~Chinese()"<<endl; }
};

int main(int argc, char **argv)
{
	Human* h = new Human;
	Englishman* e = new Englishman;
	Chinese* c = new Chinese;

	Human *p[3] = {h, e, c};

	for (int i = 0; i < 3; i++)
	{
		p[i]->eating();
		delete p[i]; // 这里最终调用的都是基类Human的析构函数
	}

	return 0;
}

上面将子类对象指针赋值给父类对象指针后,再用delete销子类对象时,调用的都是父类的析构函数。
为了避免上面的情况,想要delete时调用子类自己的析构函数时,就必须将父类和子类的析构函数声明为virtual。
(注:这里delete子类对象时会先调用子类析构函数再调用父类析构函数。)
8. 重载:函数参数不同,不可设为虚函数
覆盖:函数参数、返回值相同,可以设为虚函数
注:返回值例外:函数参数相同,但是返回值是当前对象的指针或引用时,也可以设为虚函数。

class Human {
public:
	virtual Human* test(void) { cout<<"Human's test"<<endl; return this;} 
};

class Englishman : public Human { 
public:
	virtual Englishman* test(void) { cout<<"Englishman's test"<<endl; return this; }
};

class Chinese : public Human {
public:
	virtual Chinese* test(void) { cout<<"Chinese's test"<<endl; return this; }
};

void test_return(Human& h) { h.test(); }

int main(int argc, char **argv)
	Englishman e;
	Chinese c;
	test_return(e);
	test_return(c);

	return 0;
}

总结:多态就是使用同样的外部接口对传入的父类和子类对象做处理时各自调用到父类和子类同名函数(子类要先复写父类函数)。

二、使用步骤

1.引入库

代码如下(示例):

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

2.读入数据

代码如下(示例):

data = pd.read_csv(
    'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())

该处使用的url网络请求的数据。


总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值