C++学习笔记(3)-重载与多态
来源:互联网 发布:淘宝助理宝贝图片尺寸 编辑:程序博客网 时间:2024/06/05 07:33
C++中的函数重载
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。
例子:
#include <iostream>using namespace std;class printData { public: void print(int i) { cout << "Printing int: " << i << endl; } void print(double f) { cout << "Printing float: " << f << endl; } void print(char* c) { cout << "Printing character: " << c << endl; }};int main(void){ printData pd; // Call print to print integer pd.print(5); // Call print to print float pd.print(500.263); // Call print to print character pd.print("Hello C++"); return 0;}
结果:
Printing int: 5Printing float: 500.263Printing character: Hello C++
函数重载只要函数传入变量不同即可。
C++中的运算符重载
格式:
<返回类型说明符> operator <运算符符号>(<参数表>) { <函数体> }
当运算符重载为类的成员函数时,函数的参数个数比原来的操作个数要少一个;当重载为类的友元函数时,参数个数与原操作数个数相同。原因是重载为类的成员函数时,如果某个对象使用重载了的成员函数,自身的数据可以直接访问,就不需要再放在参数表中进行传递,少了的操作数就是该对象本身。而重载为友元函数时,友元函数对某个对象的数据进行操作,就必须通过该对象的名称来进行,因此使用到的参数都要进行传递,操作数的个数就不会有变化。
例子:
#include <stdio.h>using namespace std;class Point { private: int x; public: Point(int x1) { x=x1;} const Point operator+(const Point& p);//使用成员函数重载加号运算符 friend const Point operator-(const Point& p1,const Point& p2);//使用友元函数重载减号运算符 }; const Point Point::operator+(const Point& p) { return Point(p.x+x); } Point const operator-(const Point& p1,const Point& p2) { return Point(p1.x-p2.x); } int main(){ Point a(1); Point b(2); a+b; //正确,调用成员函数 a-b; //正确,调用友元函数 a+1; //正确,先调用类型转换函数,把1变成对象,之后调用成员函数 a-1; //正确,先调用类型转换函数,把1变成对象,之后调用友元函数 1+a; //错误,调用成员函数时,第一个操作数必须是对象,因为第一个操作数还有调用成员函数的功能 1-a; //正确,先类型转换 后调用友元函数 return 0;}
可以写成
#include <stdio.h>using namespace std;class Point { private: int x; public: Point(int x1) { x=x1;} const Point operator+(const Point& p) { Point t(0); t.x=this->x+p.x; return t; }//使用成员函数重载加号运算符 friend const Point operator-(const Point& p1,const Point& p2) { Point m(1); m.x=p1.x+p2.x; return m; }//使用友元函数重载减号运算符 }; int main(){ Point a(1); Point b(2); a+b; //正确,调用成员函数 a-b; //正确,调用友元函数 a+1; //正确,先调用类型转换函数,把1变成对象,之后调用成员函数 a-1; //正确,先调用类型转换函数,把1变成对象,之后调用友元函数 1+a; //错误,调用成员函数时,第一个操作数必须是对象,因为第一个操作数还有调用成员函数的功能 1-a; //正确,先类型转换 后调用友元函数 return 0;}
注意,应当注意在类中应该使用this指针,并且一旦构造函数是初始化函数,生命的函数一定要设定一个值,不然会报错
多态
当基类和派生类有相同的函数名,如果不使用“virtual”关键字,那么将会导致基类和派生类都是调用基类中的函数,例子如下:
#include <iostream> using namespace std;class Shape {protected: int width, height;public: Shape(int a = 0, int b = 0) { width = a; height = b; } int area() { cout << "Parent class area :" << endl; return 0; }};class Rectangle : public Shape {public: Rectangle(int a = 0, int b = 0) :Shape(a, b) { } virtual int area() { cout << "Rectangle class area :" << endl; return (width * height); }};class Triangle : public Shape {public: Triangle(int a = 0, int b = 0) :Shape(a, b) { } int area() { cout << "Triangle class area :" << endl; return (width * height / 2); }};// 程序的主函数int main(){ Shape *shape,sha; Rectangle rec(10, 7),*rect; Triangle tri(10, 5),*tria; // 存储矩形的地址 shape = &rec; // 调用矩形的求面积函数 area shape->area(); //正常调用 rec.area(); //同类型指针 rect = &rec; rect->area(); cout << endl; //rect = &sha; 不能够将基类的地址赋值给派生类型的指针 // 存储三角形的地址 shape = &tri; // 调用三角形的求面积函数 area shape->area(); //正常调用 tri.area(); //同类型指针 tria = &tri; tria->area(); return 0;}
执行的结果如下:
Parent class area :Rectangle class area :Rectangle class area :Parent class area :Triangle class area :Triangle class area :
导致错误输出的原因是,调用函数 area() 被编译器设置为基类中的版本,这就是所谓的静态多态,或静态链接 - 函数调用在程序执行前就准备好了。有时候这也被称为早绑定,因为 area() 函数在程序编译期间就已经设置好了。
此外派生类变量的地址能够赋值给基类指针,但是基类变量的地址不能赋值给派生类地址,同态仅仅发生在派生类变量的地址赋值给基类指针的情况下,如果派生类变量的地址赋值给派生类变量的指针就不会发生这种情况例如
#include <iostream.h>class Base{public:virtual void f(float x){ cout << "Base::f(float) " << x << endl; }void g(float x){ cout << "Base::g(float) " << x << endl; }void h(float x){ cout << "Base::h(float) " << x << endl; }};class Derived : public Base{public:virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }void g(int x){ cout << "Derived::g(int) " << x << endl; }void h(float x){ cout << "Derived::h(float) " << x << endl; }};void main(void){Derived d;Base *pb = &d;Derived *pd = &d;// Good : behavior depends solely on type of the objectpb->f(3.14f); // Derived::f(float) 3.14pd->f(3.14f); // Derived::f(float) 3.14// Bad : behavior depends on type of the pointerpb->g(3.14f); // Base::g(float) 3.14pd->g(3.14f); // Derived::g(int) 3 (surprise!)// Bad : behavior depends on type of the pointerpb->h(3.14f); // Base::h(float) 3.14 (surprise!)pd->h(3.14f); // Derived::h(float) 3.14}
但现在,让我们对程序稍作修改,在 Shape 类中,area() 的声明前放置关键字 virtual,如下所示:
class Shape { protected: int width, height; public: Shape( int a=0, int b=0) { width = a; height = b; } virtual int area() { cout << "Parent class area :" <<endl; return 0; }};
结果如下:
Rectangle class area :Rectangle class area :Rectangle class area :Triangle class area :Triangle class area :Triangle class area :
注意!virtual针对的只是函数指针类型,当一个派生类的指针访问的时候才会出现以上的问题,当使用“.”来访问的时候,那么输出的还是变量对应的类型
此外,virtual只是解决同态问题,shape的类型仍然可以调用
如果加上
shape = &sha; shape->area(); sha.area(); cout << endl;
那么输出是:
Parent class area :Parent class area :Rectangle class area :Rectangle class area :Rectangle class area :Triangle class area :Triangle class area :Triangle class area :
参考文献:http://blog.csdn.net/djh512/article/details/8973606
virtual 的作用效果是对后面的有效例如
#include <iostream> using namespace std;class GrandFather{public: GrandFather() {} void fun() { cout << "GrandFather call function!" << endl; }};class Father : public GrandFather{public: Father() {} void fun() { cout << "Father call function!" << endl; }};class Son : public Father{public: Son() {} void fun() { cout << "Son call function!" << endl; }};void print(GrandFather* father){ father->fun();}int main(){ Father * pfather = new Son; pfather->fun(); GrandFather * pgfather = new Father; print(pgfather); return 0;}
输出的结果是
Father call function!GrandFather call function!
如果在class GrandFather类中加入virtual,那么以他为基础的派生类都有效,即如果将class GrandFather加入virtual,如下
class GrandFather{public: GrandFather() {} virtual void fun() { cout << "GrandFather call function!" << endl; }};
输出的是
Son call function!Father call function!
如果在class Father中加入virtual,其他的都不加,那么其结果是
Son call function!GrandFather call function!
如果在 class Son加上virtual,其结果是
Father call function!GrandFather call function!
如果加入两个virtual 如下
#include <iostream> using namespace std;class GrandFather{public: GrandFather() {} void fun() { cout << "GrandFather call function!" << endl; }};class Father : public GrandFather{public: Father() {} virtual void fun() { cout << "Father call function!" << endl; }};class Son : public Father{public: Son() {} virtual void fun() { cout << "Son call function!" << endl; }};void print(GrandFather* father){ father->fun();}int main(){ Father * pfather = new Son; pfather->fun(); GrandFather * pgfather = new Father; print(pgfather); return 0;}
结果是
Son call function!GrandFather call function!
也就是说,virtual只能够向派生类的方向有效,只能向“上”,对“下”是无效的,基类在“下”,派生类在“上”
纯虚函数主要是在基类中声明以便在派生类中使用,他不能够被初始化。
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”
virtual void funtion1()=0
此外,不能对友元函数使用虚函数处理;
对每个派生类中的相同函数,都要进行声明
例如
#include <iostream> using namespace std;class GrandFather{public: GrandFather() {} virtual void fun() = 0;};class Father : public GrandFather{public: Father() {} void fun() { cout << "Father call function!" << endl; }};class Son : public Father{public: Son() {} void fun() { cout << "Son call function!" << endl; }};void print(GrandFather* father){ father->fun();}int main(){ Father * pfather = new Son; pfather->fun(); GrandFather * pgfather = new Father; //指针允许 GrandFather *gp1;//不指针允许 GrandFather gp2;//不能够实例化 print(pgfather); return 0;}
- C++学习笔记(3)-重载与多态
- 学习小记--C++--重载与多态--6.04
- 重载与命名空间(学习笔记)
- Objective-C学习笔记(二十七)——方法的重载与重写
- 用C实现多态(重载与虚函数)
- C++:区别覆盖,重载与多态(转)
- C#学习笔记(3)----- 方法重载
- 【C++】【学习笔记】【006】函数的重载
- C++primer学习笔记-----6.4函数重载
- VB.net学习笔记(八)重载与共享
- C++Primer学习笔记第十四章(14/18)类 重载操作与转换
- 【学习笔记】转 java重载与重写
- 【JAVASE_学习笔记】函数与重载
- C++primer阅读笔记-重载运算与类型转换(可调用对象与function)
- C++primer阅读笔记-模板与泛型编程(重载与模板)
- C++学习笔记(三) 域运算符 new delete运算符 重载 name managling与extern"c" 带默认参数函数
- C++学习笔记之覆盖、重载、多态的区别
- [学习笔记]Objective-C与C学习交接(3)
- 微信小程序:新功能WXS解读(2017.08.30新增)
- C++初始化字符串
- SpringBoot系列2—整合Mybatis-plus
- coreseek和xunsearch的使用
- Kotlin中一些知识点学习
- C++学习笔记(3)-重载与多态
- docker基础命令
- Android 简单的SharedPreferences轻量型存储方式
- centos7 打开指定的端口
- 情感分析
- 23. Merge k Sorted Lists
- mysql中的tinyint,smallint,int,bigint
- struts+hibernate工作原理和简单工程创建步骤(附工程下载地址)
- 监听input内容实时变化