c++ 多态,虚函数、重载函数

c++三大特性:封装、继承、多态。封装使代码模块化,继承扩展已存在的代码,多态的目的是为了接口重用。

多态:

多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说:允许将子类类型的指针赋值给父类类型的指针(一个接口,多种方法)
C++ 支持两种多态性:编译时多态性,运行时多态性
a、编译时多态性(静态多态):通过重载函数实现
b、运行时多态性(动态多态):通过虚函数实现

多态的作用:

那么多态的作用是什么呢,封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。也就是说,不论传递过来的究竟是那个类的对象,函数都能够通过同一个接口调用到适应各自对象的实现方法

c++中共有三种实现多态的方式:第一种是函数重载;第二种是模板函数;第三种是虚函数

1.虚函数:

有virtual才可能发生动态多态现象,无virtual调用就按原类型调用

虚函数: 就是允许被其子类重新定义的成员函数,子类重新定义父类虚函数的做法,可实现成员函数的动态覆盖(Override)。

纯虚函数: 是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”

virtual void funtion()=0

抽象类: 包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能进行实例化。

纯虚函数的作用:

    a.为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。

    b.在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。

2.函数重载:

函数重载是这样一种机制:允许有不同参数的函数有相同的名字

具体一点讲就是:假如有如下三个函数:

void test(int arg){}         //函数1
void test(char arg){}         //函数2
void test(int arg1,int arg2){}    //函数3

如果在C中编译,将会得到一个名字冲突的错误而不能编译通过。在C++中这样做是合法的。可是当我们调用test的时候到底是会调用上面三个函数中的哪一个呢?这要依据你在调用时给的出的参数来决定。如下:

test(5);       //调用函数1
test(‘c‘);//调用函数2
test(4,5); //调用函数3

C++是如何做到这一点的呢?原来聪明的C++编译器在编译的时候悄悄的在我们的函数名上根据函数的参数的不同做了一些不同的记号。具体说如下:

void test(int arg)            //被标记为 ‘test有一个int型参数’
void test(char arg)           //被标记为 ‘test有一个char型的参数’
void test(int arg1,int arg2) //被标记为 ‘test第一个参数是int型,第二个参数为int型’

这样一来当我们进行对test的调用时,C++就可以根据调用时的参数来确定到底该用哪一个test函数了。噢,聪明的C++编译器。其实C++做标记做的比我上面所做的更聪明。我上面哪样的标记太长了。C++编译器用的标记要比我的短小的多。看看这个真正的C++的对这三个函数的标记:

[email protected]@[email protected]
[email protected]@[email protected]
[email protected]@[email protected]

是不是短多了。但却不好看明白了。好在这是给计算机看的,人看不大明白是可以理解的。 还记得cout吧。我们用<<可以让它把任意类型的数据输出。比如可以象下面那样:

 cout << 1;    //输出int型
 cout << 8.9; //输出double型
 cout << ‘a‘;   //输出char型
 cout << "abc";//输出char数组型
 cout << endl; //输出一个函数

cout之所以能够用一个函数名<<(<<是一个函数名)就能做到这些全是函数重载的功能。要是没有函数重载,我们也许会这样使用cout,如下:

    cout int<< 1;                //输出int型
    cout double<< 8.9;          //输出double型
    cout char<< ‘a‘;            //输出char型
    cout charArray<< "abc";     //输出char数组型
    cout function(…)<< endl;   //输出函数

为每一种要输出的类型起一个函数名,这岂不是很麻烦呀。 不过函数重载有一个美中不足之处就是不能为返回值不同的函数进行重载。那是因为人们常常不为函数调用指出返回值。并不是技术上不能通过返回值来进行重载。

3.模版函数(也有人叫函数模板):

概念:函数的内容有了,但函数的参数类型却是待定的(注意:参数个数不是待定的)

比如说一个(准确的说是一类或一群)函数带有两个参数,它的功能是返回其中的大值。这样的函数用模板函数来实现是适合不过的了。如下:

template < typename T>
T getMax(T arg1, T arg2)
{
    return arg1 > arg2 ? arg1:arg2; //代码段1
}

这就是基于模板的多态吗?不是。因为现在我们不论是调用getMax(1, 2)还是调用getMax(3.0, 5.0)都是走的上面的函数定义。它没有根据调用时的上下文不同而执行不同的实现。所以这充其量也就是用了一个模板函数,和多态不沾边。怎样才能和多态沾上边呢?用模板特化呀!象这样:

template<>
char* getMax(char* arg1, char* arg2)
{
    return (strcmp(arg1, arg2) > 0)?arg1:arg2;//代码段2
}

这样一来当我们调用getMax(“abc”, “efg”)的时候,就会执行代码段2,而不是代码段1。这样就是多态了。 更有意思的是如果我们再写这样一个函数:

char getMax(char arg1, char arg2)
{
    return arg1>arg2?arg1:arg2; //代码段3
}

当我们调用getMax(‘a’, ‘b’)的时候,执行的会是代码段3,而不是代码段1或代码段2。C++允许对模板函数进行函数重载,就象这个模板函数是一个普通的函数一样。于是我们马上能想到写下面这样一个函数来做三个数中取大值的处理:

int getMax( int arg1, int arg2, int arg3)
{
    return getMax(arg1, max(arg2, arg3) ); //代码段4
}

同样我们还可以这样写:

template <typename T>
T getMax(T arg1, T arg2, T arg3)
{
    return getMax(arg1, getMax(arg2, arg3) ); //代码段5
}

现在看到结合了模板的多态的威力了吧。比只用函数重载厉害多了

http://huqunxing.site/2016/09/08/C++%20%E4%B8%89%E5%A4%A7%E7%89%B9%E6%80%A7%E4%B9%8B%E5%A4%9A%E6%80%81/

https://my.oschina.net/zhjunjun/blog/1505594

原文地址:https://www.cnblogs.com/ymjyqsx/p/9703005.html

时间: 2024-10-07 14:37:29

c++ 多态,虚函数、重载函数的相关文章

C++ 类的多态二(函数重载--函数重写--函数重定义)

//函数重载--函数重写--函数重定义 #include<iostream> using namespace std; /* 函数重载: 必须在一个类中进行(子类无法重载父类中的函数) 子类无法重载父类的函数,父类同名函数将被子类的同名函数覆盖 重载是在编译期间根据参数类型,顺序,个数决定的函数调用 函数重写 必须发生于父类和子类之间 并且父类和子类中的函数必须有完全相同的函数签名 使用virtual声明之后能够产生多态(如果不使用virtual,那叫重定义) 多态是在运行期间根据具体对象的类

c++之函数重载(函数匹配)

Case void f(); void f(int); void f(int, int); void f(double, double = 3.14); 匹配原则: 1)其形参数量与本次调用提供的实参数量相等 2)每个实参的类型与对应的形参类型相同,或者可以转换成形参的类型; 寻找最佳匹配: 1)该函数每个实参的匹配都不劣于其他可行函数需要的匹配; 2)至少有一个实参的匹配优于其他可行函数提供的匹配; 例子: a) f(2.56,38); b) f(38); c) f(32,0); d) f(3

C++的函数重载和main函数之外的工作

今天被问到一个C++的函数重载问题,一下子没反应过来,这种基础的问题竟然忘记了,以下记录一下这些忘记的内容.     函数重载 函数重载的定义是:在相同的作用域中,如果函数具有相同名字而仅仅是形参表不同,此时成为函数重载.注意函数重载不能基于不同的返回值类型进行重载. 注意函数重载中的"形参表"不同,是指本质不同,不要被一些表象迷惑.main函数不能被重载. 下面三组定义本质是相同的,不是重载: 1)int sum (int &a); 和 int sum (int &)

【Cpp】考点·函数重载

一.什么是函数重载 函数重载(overloaded)是指,在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数.这组函数被称为重载函数.重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处. 举个栗子 1 #include<iostream> 2 using namespace std; 3 4 void print(int i) 5 { 6 cout << "print a integer: &qu

C++学习笔记(十二):重载函数

1. 什么是重载函数 假设同一作用域内的几个函数名字同样但形參列表不同.那么这些函数就称之为--重载函数. 比如: void print( const char *cp); void print(const int *begin , const int *end); void print(const int ia[], int size); 上面的这些构造函数运行的操作很的相似.都是打印一些数据.可是接受的形參却不一样. 当调用这些函数时,编译器会依据传递的实參类型判断想要运行的是哪个函数. 比

C++ 学习之函数重载、基于const的重载

函数重载 函数重载的定义是:在相同的作用域中,如果函数具有相同名字而仅仅是形参表不同,此时成为函数重载.注意函数重载不能基于不同的返回值类型进行重载. 注意函数重载中的"形参表"不同,是指本质不同,不要被一些表象迷惑.main函数不能被重载. 下面三组定义本质是相同的,不是重载: 1)int sum (int &a); 和 int sum (int &); 2)  int sum (int a) 和 int sum (const int a); 3)typedef in

C++学习笔记(八):函数重载、函数指针和函数对象

函数重载 函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数.重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处. 试想如果没有函数重载机制,如在C中,你必须要这样去做:为这个print函数取不同的名字,如print_int.print_string.这里还只是两个的情况,如果是很多个的话,就需要为实现同一个功能的函数取很多个名字,如加入打印long型.char*.各种类型的数组等等.

函数重载总结

函数重载 函数重载的定义是:在相同的作用域中,如果函数具有相同名字而仅仅是形参表不同,此时成为函数重载.注意函数重载不能基于不同的返回值类型进行重载. 注意函数重载中的"形参表"不同,是指本质不同,不要被一些表象迷惑.main函数不能被重载. 重载确定的三个步骤: 1,候选函数 2,选择可行函数 3,寻找最佳匹配 4,含有多个形参的重载确定 下面三组定义本质是相同的,不是重载: 1)int sum (int &a); 和 int sum (int &); 2)  int

C++--友元函数与函数重载

一.友元函数 友元的介绍1.友元是C++中的一种关系2.友元关系发生在函数与类之间或者类与类之间3.友元关系是单项的,不能传递友元的用法1.在类中以friend关键字声明友元2.类的友元可以是其它类或者具体函数3.友元不是类的一部分4.友元不受类中访问级别的限制5.友元可以直接访问具体类的所有成员示例 #include <stdio.h> #include <math.h> class Point { double x; double y; public: Point(double

为什么C++支持函数重载而C不允许

首先我们要了解什么是函数重载:函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题. 那么问题来了,C++究竟比C强大到哪里了呢?为什么C就不允许我们命名多个同名函数呢. 其实如果在我们运行这些函数时转到编译看一看,就会明白.C++在底层运行这些函数时,会重新给这些函数起一个包含其参数列表的名字(不同平台命名规则不同),这样一来程序在编译时,根据重载的条件 - 形