栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++总结笔记(九)—— 多态

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++总结笔记(九)—— 多态

文章目录

一、多态是什么?二、使用步骤

2.1. 静态多态

2.1.1 函数重载2.1.2 模板 2.2.动态多态

2.2.1 示例2.2.2 原理分析 总结


一、多态是什么?

多态是面向对象的语言中都必须掌握的特性,其概念简单讲就是对同一种特性的方法有不同的实现功能,例如玩手机这个方法,有人玩抖音,有人玩LOL等等种不同的应用形式。
多态可以按照绑定分为静态多态和动态多态。
绑定是指函数体与函数调用完成关联的过程。
静态多态是指在程序编译期间就完成,一般通过函数重载和模板来完成,会根据函数实参的类型或个数来选择那个函数来实现。
动态多态是指在程序编译后完成的联编,通过虚方法的形式完成,根据引用对象的实际类型调用相应的方法。其原理就是用父类的虚函数指针去调用子类中被重写的方法。

二、使用步骤 2.1. 静态多态 2.1.1 函数重载

下面为构造函数重载示例:

class Cat
{
public:
	Cat()
	{
		cout << "喵是无参构造函数" << endl;
	}

	Cat(string name)
	{
		Name = name;
		cout << "喵是有参构造函数" << endl;
	}
    //用于拷贝c的属性值,用常量引用的方式进行
	Cat(const Cat &c)
	{
		Name = c.Name;
		cout<< "喵是拷贝构造函数" << endl;
	}

	~Cat()
	{
		cout << "喵是析构函数" << endl;
	}

	string Name;//咪咪名字
};

void FindName()
{
	//括号法
	Cat cat1;//用默认构造函数时,不能加括号,否则编译器会当作函数声明。
	Cat cat2(cat1);//拷贝构造函数调用
	Cat cat3("小300");//有参构造函数调用。
	Cat cat4(cat3);//拷贝构造函数调用
	
	cout << "第一个猫的名字是:" << cat1.Name << endl;
	cout << "第二个猫的名字是:" << cat2.Name << endl;
	cout << "第三个猫的名字是:" << cat3.Name << endl;
	cout << "第四个猫的名字是:" << cat4.Name << endl;
}
2.1.2 模板

模板在C++中分为类模板和函数模板,用template修饰,和泛型的概念很相似。

类模板是通过建立一个通用类,其中的数据成员、成员函数的返回值类型和形参类型不进行具体指定,用一个虚拟的类型声明。在使用类模板定义对象时,系统会实参的类型来取代类模板中虚拟类型从而实现了不同类的功能。

函数模板也需声明一个模板类名,然后在函数形参中声明一个模板类对象,在进行函数调用时会根据实参的类型来覆盖模板类。

函数模板调用规则:
1.如果函数模板和普通函数都可以实现功能的话优先调用普通函数。
2.可以通过空模板参数列表来强制调用函数模板。
3.函数模板可以发生重载。
4.如果函数模板可以产生更好的匹配,优先调用函数模板。

类模板和函数模板的区别:
1:类模板没办法对声明的模板类对象进行自动推导类型,必须用指定类型,函数模板可以。
2:类模板在模板参数声明时可以有默认参数类型,比如在声明构造函数时一个形参为模板类型,一个为int类型。

类模板

#include 
#include
using namespace std;

template

class Person
{
public:
	Person(T1 name, T2 age)
	{
		this->m_age = age;
		this->m_name = name;
	}

	void showPerson()
	{
		cout << m_name <<" "<< m_age << endl;
	}

private:
	T1 m_name;
	T2 m_age;
};


int main()
{
	Person p("张三", 1);
	p.showPerson();

	system("pause");
	return 0;
}

函数模板

#include 
using namespace std;

template

//T的类型需要一致,选择排序
void Sort(T arr[], int l)
{
	for (int i = 0; i < l; i++)
	{
		int max = i;
		for (int j = i + 1; j < l; j++)
		{
			if (arr[max] > arr[j])
			{
				max = j;
			}
		}

		if (max != i)
		{
			T temp = arr[max];
			arr[max] = arr[i];
			arr[i] = temp;
		}
	}
}

int main()
{
	int Array[] = {1,4,35,24,213,2132};
	int num = sizeof(Array) / sizeof(int);
	Sort(Array, num);
	//Sort<>(Array, num);//空模板参数列表
	for(int i = 0; i< num; i++)
	{
		cout << Array[i] << endl;
	}

	system("pause");
	return 0;
}
2.2.动态多态

动态多态需满足以下条件:
1.类之间存在继承关系
2. 调用函数的对象必须是指针或者引用。
3.子类重写父类函数(函数返回值、名称和参数列表相同)

2.2.1 示例
#include
using namespace std;

class Student
{
public:
    //虚函数
    virtual void play()
    {
        cout << "我在玩手机" << endl;
    }
    //纯虚函数,纯虚函数的类为抽象类,类无法实例化
    

    //父类写虚析构函数
    virtual ~Student()
    {

    }
};

class Student1 :public Student
{
public:
    Student1(string app)
    {
        APP = new string(app);
    }

    void play()
    {
        cout << "我在刷" << *APP << endl;
    }
    //如果没有在堆区开辟内存的化,不用写
    ~Student1()
    {
        if (APP != NULL)
        {
            delete APP;
            APP = NULL;
        }
    }

private:
    string *APP;
};

class Student2 :public Student
{
public:
    Student2(string app)
    {
        APP = new string(app);
    }

    void play()
    {
        cout << "我在玩" << *APP << endl;
    }

    ~Student2()
    {
        if (APP != NULL)
        {
            delete APP;
            APP = NULL;
        }
    }
private:
    string* APP;
};

int main()
{
    //父类指针在调用自身的析构函数时,不会调用子类的析构,从而造成内存泄露,所以要改为虚析构的方法。
    Student* s1 = new Student1("抖音");
    s1->play();
    delete s1;
   
    Student* s2 = new Student2("LOL");
    s2->play();
    delete s2;
}
2.2.2 原理分析

同样可以使用开发者工具进行分析。

其中vfptr指的是虚函数指针,vftable指的是虚函数表,父类子类中均存在虚函数指针和表,其中指针指向虚函数表。在进行虚函数的重写时,就会产生子类的虚函数指针,通过声明父类指针或引用调用函数时,就会覆盖vftable中类名,指向对应子类中的重写方法。


总结

多态的概念使C++的编程非常灵活,需要特别注意开闭原则和内存管理。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/737970.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号