学习C++中的多态

一、概念

多态是面向对象程序设计的三大特征之一。封装性是基础,继承性是关键,多态性是补充,而多态又存在于继承的环境之中。多态性的含义就是多种状态。C++语言中支持两种多态性。一种是函数重载和运算符重载,又被称为静态多态,另一种是动态联编和虚函数,被称为动态多态。在这里主要讨论第一种和第二种的虚函数。

1.函数重载

函数重载简单的说就是给一个函数名多个含义。C++语言中允许在相同的作用域内以相同的名字定义几个不同实现的函数。定义这种重载函数时要求函数的参数或者至少有一个类型不同,或者个数不同,或者顺序不同。参数个数和类型,顺序都相同,仅返回值不同的重载函数是非法的。因为编译程序在选择相同名字的重载函数是仅考虑函数参数列表,即要根据函数参数列表中的参数个数、参数类型或参数顺序的差异进行选择。

举例:string类的构造函数重载(编译环境:VS2013)

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#include <string.h>
class String
{
public:
	String(char *s)
	{
		length = strlen(s);
		ps = new char[length + 1];
		strcpy(ps, s);
	}

	String(string &s)
	{

		length = s.length;
		ps = new char[length + 1];
		strcpy(ps, s.ps);
	}

	String(int size = 20)
	{
		length = size;
		ps = new char[length + 1];
		*ps = ‘\0‘;
	}
	~String()
	{
		delete ps;
	}

	int getlen()
	{
		return length;
	}

	void print()
	{
		cout << ps << endl;
	}
private:
	char* ps;
	int length;

};

int main()
{
	String str1("String");
	str1.print();
	cout << str1.getlen() << endl;

	char *ps1 = "String Pionter";
	String str2(ps1);

	String str3(str2);
	str3.print();
	cout << str3.getlen() << endl;

	system("pause");
	return 0;
}

String类的构造函数被重载了三次,

str1("String")调用构造函数String(char *s);

str2(ps1)调用构造函数String(char *s);

str3(str2)调用构造函数String(String);

2.运算符重载

运算符重载重载就是赋予已有的运算符多重定义,使它具多种多种功能。

定义方法:类名 operator运算符(参数列表){ }

下面的运算符在C++中允许重载:

  • 算数运算符: +, -, *, /, %, ++, --
  • 位操作运算符: &,|, ~, ^, <<,>>
  • 逻辑运算符: !, &&, ||
  • 比较运算符: <, >, <=, >=, ==, !=
  • 赋值运算符: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
  • 其它运算符: [], (), ->, ‘, new, delete, new[], delete[]

下列运算符不允许重载:

·,·*, ::,?

使用运算符重载的注意:

  1. 用户重新定义运算符时,不改变原运算符的优先级和结合性。不改变运算符的操作数个数和语法结构,单目运算符只能重载为单目运算符,双目运算符只能重载双目运算符。
  2. 重载运算符不能有二义性。

运算符重载举例:

//运算符重载

#include <iostream>

using namespace std;

class Complex

{

	//friend Complex operator+(Complex c1, Complex c2);

public:
	Complex(double real = 0.0, double image = 0.0)
		: _real(real)
		, _image(image)

	{}
	Complex(const Complex& c)
		: _real(c._real)
		, _image(c._image)
	{}

	Complex operator+(const Complex& c1)
	{
		return Complex(_real + c1._real, _image + c1._image);
	}

	Complex operator-(const Complex& c1)
	{
		return Complex(_real - c1._real, _image - c1._image);
	}

	Complex operator*(const Complex& c1)
	{

		return Complex(_real*c1._real - _image*c1._image, _real*c1._image + _image*c1._real);
	}

	Complex operator/(const Complex& c1)
	{
		return Complex((_real*c1._real + _image*c1._image) / (c1._image*c1._image + c1._real*c1._real), (_image*c1._real - _real*c1._image) / (c1._image*c1._image + c1._real*c1._real));
	}

	Complex& operator+=(const Complex& c1)
	{
		_real = _real + c1._real;
		_image = _image + c1._image;
		return *this;
	}

	Complex& operator-=(const Complex& c1)
	{
		_real = _real - c1._real;
		_image = _image - c1._image;
		return *this;
	}

	Complex& operator*=(const Complex& c1)
	{
		double tmp = _real;
		_real = _real*c1._real - _image*c1._image;
		_image = tmp*c1._image + _image*c1._real;
		return *this;
	}

	Complex& operator/=(const Complex& c1)
	{
		double tmp = _real;
		_real = (_real*c1._real + _image*c1._image) / (c1._image*c1._image + c1._real*c1._real);
		_image = (_image*c1._real - tmp*c1._image) / (c1._image*c1._image + c1._real*c1._real);
		return *this;
	}

	// 只比较实部

	bool operator<(const Complex& c)
	{
		if (_real<c._real)
		{
			return true;
		}
		else
		{
			return false;
		}

	}

	bool operator>(const Complex& c)
	{
		if (_real>c._real)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	bool operator<=(const Complex& c)
	{
		if ((_real<c._real) || (_real == c._real))
		{
			return true;
		}
		else
		{
			return false;
		}

	}

	Complex& operator=(const Complex& c)
	{
		if (this != &c)
		{
			_real = c._real;
			_image = c._image;
		}
		return *this;
	}

	bool operator==(const Complex& c)
	{
		return _real == c._real && _image == c._image;

	}

	bool operator&&(const Complex& c)
	{
		return true;
	}

	// 前置

	Complex& operator++()
	{
		_real++;
		_image++;
		return *this;
	}

	// 后置++

	Complex operator++(int)
	{
		Complex temp(*this);
		_real++;
		_image++;
		return temp;
	}

	Complex& operator--()
	{
		_real--;
		_image--;
		return *this;
	}

	Complex operator--(int)
	{

		Complex temp(*this);
		_real--;
		_image--;
		return temp;
	}

	void display()
	{
		cout << _real << "," << _image << "i" << endl;
		cout << endl;
	}

private:
	double _real;
	double _image;
};

int main()
{
	Complex c1(1, 1);

	Complex c2(2, 1);

	Complex c3;

	Complex c4(1, 1);

	Complex c5(1, 1);

	bool bo = true;

	c3 = c1 + c2;
	cout << "c3 = c1 + c2  " << endl;
	c3.display();

	c3 = c1 - c2;

	cout << "c3 = c1 - c2  " << endl;

	c3.display();

	c3 = c2*c1;

	cout << "c3 = c1 * c2  " << endl;

	c3.display();

	c3 = c2 / c1;

	cout << "c3 = c1 / c2  " << endl;

	c3.display();

	c1 += c2;

	cout << " c1 += c2  " << endl;

	c1.display();

	c1 -= c2;

	cout << " c1 -= c2  " << endl;

	c1.display();

	c1 *= c2;

	cout << " c1 *= c2  " << endl;

	c1.display();

	c1 /= c2;

	cout << " c1 /= c2  " << endl;

	c1.display();

	bo = c1 < c2;

	if (bo)
	{
		cout << "c1 < c2 is true" << endl;
	}

	else
	{
		cout << "c1 < c2 is false" << endl;
	}

	c4++;

	cout << " c4++  " << endl;

	c4.display();

	++c5;

	cout << " ++c5  " << endl;

	c5.display();

	c4--;

	cout << " c4--  " << endl;

	c4.display();

	--c5;

	cout << " -c5  " << endl;

	c5.display();
	system("pause");
	return 0;

}

对复数的四则运算,++,--(前置,后置)等进行了重载。

3.虚函数

使用virtual关键字修饰函数时,指明该函数为虚函数,派生类需要重新实现,编译器将实现动态绑定。

总结:

1、派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同。(协变除外)

2、基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性。

3、只有类的成员函数才能定义为虚函数,静态成员函数不能定义为虚函数。

4、如果在类外定义虚函数,只能在声明函数时加virtual关键字,定义时不用加。

5、构造函数不能定义为虚函数,虽然可以将operator=定义为虚函数,但最好不要这么做,使用时容易混淆

6、不要在构造函数和析构函数中调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会出现未定义的行为。

7、最好将基类的析构函数声明为虚函数。(析构函数比较特殊,因为派生类的析构函数跟基类的析构函数名称不一样,但是构成覆盖,这里编译器做了特殊处理)

8、虚表是所有类对象实例共用的。

时间: 2024-10-21 06:12:21

学习C++中的多态的相关文章

C++语言学习(九)——多态

C++语言学习(九)--多态 C++中所谓的多态(polymorphism)是指由继承而产生的相关的不同的类,其对象对同一消息会作出不同的响应.    多态性是面向对象程序设计的一个重要特征,能增加程序的灵活性.可以减轻系统升级,维护,调试的工作量和复杂度. 多态是一种不同层次分类下的重要联系,是一种跨层操作. 一.多态实现的前提 赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代.赋值兼容是一种默认行为,不需要任何的显式的转化步骤,只能发生在public继承方式中,是多态

java中实现多态的机制是什么?

多态性是面向对象程序设计代码重用的一个重要机制,我们曾不只一次的提到Java多态性.在Java运行时多态性:继承和接口的实现一文中,我们曾详细介绍了Java实现运行时多态性的动态方法调度:今天我们再次深入Java核心,一起学习Java中多态性的实现. “polymorphism(多态)”一词来自希腊语,意为“多种形式”.多数Java程序员把多态看作对象的一种能力,使其能调用正确的方法版本.尽管如此,这种面向实现的观点导致了多态的神奇功能,胜于仅仅把多态看成纯粹的概念. Java中的多态总是子类型

Java语言中的----多态和异常处理

day13 Java语言中的----多态和异常处理 一.概述: 学习Java语言就要理解Java中的面向对象的四大特征:分别是封装.抽象.继承.多态.前面三个我们已经学完了,下面我们来学一下多态.什么是多态?不明思议就是具有两种形态性,一个方法可以定义两种形态,这就是方法的多态性.同时我们还会学习到什么是方法重载.和方法签名. 异常处理就是在编译的时候需要我们手动的去处理一下编译都不能够通过的程序.使用try {} catch{}结构就可以处理异常. 二.多态: 1.所有类的基类是object,

C++语言学习(十一)——多态

C++语言学习(十一)--多态 一.多态简介 C++中的多态(polymorphism)是指由继承而产生的相关的不同的类,其对象对同一消息会作出不同的响应.多态性是面向对象程序设计的一个重要特征,能增加程序的灵活性.可以减轻系统升级,维护,调试的工作量和复杂度.多态是一种不同层次分类下的重要联系,是一种跨层操作. 二.多态实现的前提 赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代.赋值兼容是一种默认行为,不需要任何的显式的转化步骤,只能发生在public继承方式中,是多

java中的多态

多态是什么 1:在面向对象的程序设计中,多态是继继承和封装之后的第三大特征. 2:base类和导出类中有相同方法时,先调导出类的方法. 3:多态的作用是消除base类和导出类的耦合: 多态产生的条件 1 存在继承关系 2子类重写base类方法 3base类的引用指向子类 class Aa{ public void f(){ System.out.println("A.f()"); } } class B extends Aa{ public void f(){//子类重写base类方法

如何理解并学习javascript中的面向对象(OOP) [转]

如果你想让你的javascript代码变得更加优美,性能更加卓越.或者,你想像jQuery的作者一样,写出属于自己优秀的类库(哪怕是基于 jquery的插件).那么,你请务必要学习javascript面向对象,否则你无法更灵活的使用javascript这门语言. 什么事闭包?到底什么是原型?(知道闭包和原型的,就算得上是javascript的高手了.但真正能够理解,并且灵活运用的人并不多)到底该如何学习javascript中的面向对象呢?在javascript这么语言正如日中天,相信不少人正在为

Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍

1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过start方法启动线程--->线程变为可运行可执行状态,然后通过数据产生共享,线程产生互斥---->线程状态变为阻塞状态---->阻塞状态想打开的话可以调用notify方法. 这里Java5中提供了封装好的类,可以直接调用然后构造阻塞状态,以保证数据的原子性. 2.如何实现? 主要是实现Blo

什么是c++中的多态

什么是c++中的多态 引言 多态(Polymorphism).封装(Encapsulation)和继承(Inheritance)是面向对象思想的"三大特征",此处俗称"面向对象的三板斧",而多态是三板斧中最厉害的杀招,是面向对象最精微的内功,可以说,不理解多态就不懂得什么是面向对象. 定义 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果. 简单地概括为"一个接口,多种方法". 类别 (1)编译时的多态性. ??编译时的多态性是通过

开源学习--SlideExpandableListView中的列表项动画实现框架分析

前面的话 开源项目Android-SlideExpandableListView是一个简单的介绍列表项动画展示的小型项目,分析这个项目可以对自定义框架及列表类动画实现有个比较清晰的认识,工作中中时常根据需求扩展定义自己的适配器,虽然具体需求不同,但架构类似,本文把最近关于该开源项目的研究心得整理分享,共同学习~ 项目简介 github地址https://github.com/tjerkw/Android-SlideExpandableListView 这是个入门级的列表项动画展示框架,实现效果如