C++:多态性

多态性的两种类型

  • 静态多态性
    • 编译时
    • 静态联编
    • 函数/运算符重载
  • 动态多态性
    • 运行时
    • 动态联编
    • 继承、虚函数、基类的指针或引用
    • 在编译时无法确定调用的是哪个同名函数

静态多态性

缺点:不够灵活

优点:调用速度快,效率高

  • 函数重载
    • 同一个类中多个成员函数
    • 基类和派生类中的同名函数之间

 同一个类中多个成员函数

#include <iostream>
#include <string>
using namespace std;

class Student
{
private:
    string name;
    int sort;
public:
    Student();
    Student(string sname, int n);
    
    void print();
    void print(int n);    
};

Student::Student()
{
    name = "Unknown";
    sort = 18;
}

Student::Student(string sname, int n)
{
    name = sname;
    sort = n;
}

void Student::print()
{
    cout << "Name: " << name << endl;
    cout << "Sort: " << sort << endl;
}

void Student::print(int n)
{
    cout<<"Number: "<< n << sort <<endl;
}

int main() 
{
    Student s1;
    Student s2("John", 20);
    s1.print();
    s2.print();
    s2.print(2024);
    return 0;
}

基类和派生类中的同名函数之间

#include <iostream>
using namespace std;

class A
{
public:
    double get_value(double a,double b)
    {
        return a;
    }
};

class B: public A
{
public:
    double get_value(double c)
    {
        return c;
    }
};

int main()
{
    A obj1;
    B obj2;
    cout<<obj1.get_value(2.5,3.5)<<endl;
    cout<<obj2.get_value(3.2)<<endl;
    cout<<obj2.A::get_value(4.7,2.6)<<endl;
    return 0;
}

运算符重载

本质是函数重载

对已有 运算符赋予多重含义,同一个运算符作用于不同类型的数据将会产生不同的行为

不可以重载的运算符:

. 成员提取符

.* 成员指针运算符

:: 作用域修饰符

?: 条件运算符

sizeof 长度运算符

 重载之后,运算符的优先级和结合性都不会改变

运算符重载不能改变原运算符的操作对象个数,且至少要有一个操作对象属于自定义类型

运算符重载方式:类中成员函数,类的友元函数

只能成员函数:=,(),[],->

只能友元函数:提取符>>,插入符<<

用成员函数重载运算符

第一运算对象必须是本类的对象,否则只能通过友元函数重载

#include <iostream>
using namespace std;

class Complex
{
private:
	float real;
	float imag;
public:
	Complex(float r = 0, float i = 0);
	void print();
	Complex operator + (const Complex& a);
	Complex operator + (float x);
	Complex operator ++ ();	//单目不需要形参
};

Complex::Complex(float r, float i)
{
	real = r;
	imag = i;
}

void Complex::print()
{
	cout << real;
	if (imag != 0)
	{
		if (imag > 0)
			cout << "+";
		cout << imag << "i";
	}
	cout << endl;
}

Complex Complex::operator+(const Complex& a)
//形参为第二运算对象
{
	Complex temp;
	temp.real = real + a.real;
	temp.imag = imag + a.imag;
	return temp;
}

Complex Complex::operator+(float x)
{
	return Complex(real+x,imag+x);	//虚部和实部同时加x
}

Complex Complex::operator++()
{
	++real;
	++imag;
	return *this;
}

int main()
{
	Complex c1(1.5, 2.5), c2(5, 10), c3, c4;
	cout << "original c1 is:" ;
	c1.print();
	cout << "original c2 is:";
	c2.print();
	
	c3 = c1 + c2;
	cout << "c3=c1+c2 is:";
	c3.print();

	c3 = c3 + 5.32f;
	cout << "c3+5.32f is:";
	c3.print();

	c4 = ++c2;
	cout << "after ++c2 c2 is:";
	c2.print();
	cout << "after ++c2 c4 is:";
	c4.print();

	return 0;
}

用友元函数重载运算符

第一个操作数不是本类对象

提取运算符 >>

插入运算符 <<

#include <iostream>
using namespace std;

class Complex
{
private:
    float real, imag;
public:
    Complex(float r=0,float i=0);
    void print();
    friend Complex operator+(const Complex &a,const Complex &b);
    friend Complex operator+(const Complex &a,float x);
    friend Complex operator++(Complex &a);
};

Complex::Complex(float r,float i)
{
    real=r;
    imag=i;
}

void Complex::print()
{
    cout<<real;
    if (imag!=0)
    {
        if (imag>0)
            cout<<"+";
        cout<<imag<<"i"<<endl;
    }
    cout<<endl;    
}

Complex operator+(const Complex &a,const Complex &b)
{
    Complex temp;
    temp.real=a.real+b.real;
    temp.imag=a.imag+b.imag;
    return temp;
}

Complex operator+(const Complex &a,float x)
{
    return Complex(a.real+x,a.imag+x);
}

Complex operator++(Complex &a)
{
    ++a.real;
    ++a.imag;
    return a;
}

int main() 
{
    Complex c1(1.5,2.5),c2(5,10),c3,c4;
    cout<<"original c1:";
    c1.print();
    cout<<"original c2:";
    c2.print();

    c3=c1+c2;
    cout<<"c3=c1+c2:";
    c3.print();

    c3=c3+5.32f;
    cout<<"c3=c3+5.32f:";
    c3.print();
    
    c4=++c2;
    cout<<"after ++c2,c2:";
    c2.print();
    cout<<"after ++c2,c4:";
    c4.print();

    return 0;
}

赋值运算符"="重载

只能被重载为成员函数

不能被继承

运算对象非基本类型时,应当给出 ”=“ 运算符重载函数

#include<iostream>
using namespace std;

class CMessage
{
private:
	char* pmessage;
public:
	CMessage(const char* text = "爱我中华!")
	{
		pmessage = new char[strlen(text) + 1];
		strcpy_s(pmessage, strlen(text) + 1, text);
	}
	void show()
	{
		cout << pmessage << endl;
	}
	~CMessage()
	{
		cout << "Destructor called." << endl;
		delete[] pmessage;
	}
	CMessage& operator=(const CMessage& s);
};

CMessage& CMessage::operator=(const CMessage& s)
{
	int len = strlen(s.pmessage) + 1;
	if (pmessage)
		delete[] pmessage;
	pmessage = new char[len];
	strcpy_s(pmessage, len, s.pmessage);
	return *this;
}

int main()
{
	CMessage msg1("中国一点也不能少!");
	CMessage msg2;
	msg1.show();
	msg2.show();

	cout << "after msg2=msg1 >>>> " << endl;
	msg2 = msg1;
	msg1.show();
	msg2.show();

	return 0;
}

下标运算符"[]"的重载

可以带一个右操作数

只能使用成员函数

#include<iostream>
#include<iomanip>
using namespace std;

class Array
{
private:
	int* m;
	int num;
public:
	Array(int n=3);
	~Array();
	int& operator[](int);
	void show();
};

Array::Array(int n)
{
	num = n;
	m = new int[num];
	if (m == NULL)
	{
		cout << "allocation failure." << endl;
		exit(0);
	}
	for (int i = 0; i < num; i++)
		m[i] = i * 10 + 1;	//为数组的每个元素赋初值
}

Array::~Array()
{
	delete[] m;
}

void Array::show()
{
	for (int i = 0; i < num; i++)
		cout << setw(4) << m[i];
	cout << endl;
}

int& Array::operator[](int r)
{
	if (r > 0 && r < num)
		return *(m + r);
	return *m;
}

int main()
{
	Array ar(5);
	ar.show();

	ar[2] = 800;
	ar.show();
	
	ar[23] = -100;
	ar.show();

	return 0;
}

自增自减运算符重载

#include <iostream>
using namespace std;

class Complex
{
private:
    float real, imag;
public:
    Complex (float r=0, float i=0);
    Complex operator --();
    Complex operator --(int);
    friend Complex operator ++(Complex& a);
    friend Complex operator ++(Complex& a, int);
    friend istream& operator >> (istream& in, Complex& com);
    friend ostream& operator << (ostream& out, const Complex& com);
};

Complex::Complex(float r, float i)
{
    real = r;
    imag = i;
}

Complex Complex::operator --()
{
    real--;
    imag--;
    return *this;
}

Complex Complex::operator --(int)
{
    Complex temp = *this;
    real--;
    imag--;
    return temp;
}

Complex operator ++(Complex& a)
{
    a.real++;
    a.imag++;
    return a;
}

Complex operator ++(Complex& a, int)
{
    Complex temp = a;
    a.real++;
    a.imag++;
    return temp;
}

istream& operator >> (istream& in, Complex& com)
{
    in >> com.real >> com.imag;
    return in;
}

ostream& operator << (ostream& out, const Complex& com)
{
    out << com.real ;
    if(com.imag != 0)
    {
        if(com.imag > 0)
            out << "+";
        out << com.imag << "i";
    }
    out << endl;
    return out;
}

int main() 
{
    Complex c1(1.5,-2.5),c2(-5,10),c3,c4;
    cout<<"original c1 = "<<c1;
    cout<<"original c2 = "<<c2;
    
    c3 = ++c2;
    cout<<"after c3 = ++c2 ";
    cout<<"c2 = "<<c2;
    cout<<"c3 = "<<c3;

    c4=--c2;
    cout<<"after c4=--c2 ";
    cout<<"c2 = "<<c2;
    cout<<"c4 = "<<c4;

    c3=c1++;
    cout<<"after c3=c1++ ";
    cout<<"c1 = "<<c1;
    cout<<"c3 = "<<c3;

    c4=c1--;
    cout<<"after c4=c1-- ";
    cout<<"c1 = "<<c1;
    cout<<"c4 = "<<c4;
    return 0;
}

提取运算符">>"和插入运算符"<<"的重载

第一操作数是流对象,只能以友元函数实现

两个形参,第一个必须为输入流 istream 的引用,第二个必须为本类的对象引用,不可以用常引用或值形式参数

 两个形参,第一个必须为 输出流 ostream 的引用,第二个必须为本类的对象引用,一般用常引用参数,保护对应实参和提高效率

 必须返回流类的引用

#include <iostream>
using namespace std;

class Complex
{
private:
    float real, imag;
public:
    Complex(float r=0, float i=0);
    friend istream & operator>>(istream &in, Complex &c);
    friend ostream & operator<<(ostream &out, Complex &c);
};

Complex::Complex(float r, float i)
{
    real = r;
    imag = i;
}

istream & operator>>(istream &in, Complex &c)
{
    in >> c.real >> c.imag;
    return in;
}

ostream & operator<<(ostream &out, Complex &c)
{
    out << c.real;
    if(c.imag >= 0)
        out << "+" ;
    out << c.imag << "i";
    out << endl;
    return out;
}

int main()
{
    Complex c1(1.5, 2.5);
    Complex c2;

    cout<<"c1 = ";
    cout<<c1;

    cout<<"c2 = "<<c2;
    //cout<<(operator<<(cout, "c2=")<<c2;
    
    cout<<"input c1, c2: ";
    cin>>c1>>c2;

    cout<<"c1 = "<<c1;
    cout<<"c2 = "<<c2;

    return 0;
}

动态多态性的实现

虚函数的定义

具有继承关系(必须公有继承)

基类与派生类中的同名函数,且函数头部完全一致

必须与引用/指针一起使用

符合赋值兼容规则

 静态成员不能声明为虚函数

内联函数不能声明为虚函数

构造函数不能是虚函数

析构函数可以是虚函数,且往往被声明为虚函数

 虚析构函数

若基类的析构函数声明为虚函数,则该类的所有派生类的析构函数也自动成为虚函数而无需显式声明

#include <iostream>
using namespace std;


class Base 
{
public:
virtual ~Base();
};

class Derived : public Base 
{
private:
    char *str;
public:
    Derived(int x);
    ~Derived();
};

Base::~Base() 
{
    cout << "Base destructor called" << endl;
}

Derived::Derived(int x) 
{
    str = new char[x];
}

Derived::~Derived() 
{
    delete[] str;
    cout << "Derived destructor called" << endl;
}

int main() 
{
    Base *b = new Derived(10);
    delete b;
    return 0;
}

 虚函数与同名覆盖

#include <iostream>
using namespace std;


class Base 
{
public:
    virtual void f1()
    {
        cout<<"f1 function of Base"<<endl;
    } 
    virtual void f2()
    {
        cout<<"f2 function of Base"<<endl;
    }
    void f3()
    {
        cout<<"f3 function of Base"<<endl;
    }
};

class Derived : public Base 
{
public:
    void f1()
    {
        cout<<"f1 function of Derived"<<endl;
    }
    void f2(int x)
    {
        cout<<"f2 function of Derived "<<endl;
    }
    void f3()
    {
        cout<<"f3 function of Derived"<<endl;
    }
};

int main()
{
    Base ob1,*b;
    Derived ob2;
    b=&ob1;

    cout<<"Base ob1"<<endl;
    b->f1();
    b->f2();
    b->f3();
    
    cout<<"Derived ob2"<<endl;
    b=&ob2;
    b->f1();
    b->f2();
    b->f3();

    cout<<"f1,f2,f3 functions of Derived"<<endl;
    ob2.f1();
    ob2.f2(5);
    ob2.f3();

    return 0;
}

用派生类对象调用函数,发生同名时只能调用自身的成员函数

纯虚函数与抽象类

纯虚函数

只给出了函数的原型声明而没有具体的实现内容

在虚函数原型的最后赋值0

没有函数体

不能被调用

作用:基类给派生类提供一个标准的函数原型

#include <iostream>
using namespace std;

class Point 
{
public:
    virtual void Draw()=0;
};

class Line : public Point 
{
public:
    void Draw();
};

void Line::Draw() 
{
    cout << "Drawing a line" << endl;
}

class Circle : public Point 
{
public:
    void Draw();
};

void Circle::Draw() 
{
    cout << "Drawing a circle" << endl;
}

//functions
void DrawObject(Point* p)
{
    p->Draw();
} 

int main() 
{
    Line l;
    Circle c;
    DrawObject(&l);
    DrawObject(&c);
    return 0;
}

抽象类

至少包含一个纯虚函数的类

不能生成对象

可以定义抽象类的指针或引用

不能作为参数类型、函数返回类型、显式转换类型

基类不能是普通类

还可以定义普通成员函数或虚函数

#include <iostream>
using namespace std;
const double pi = 3.14;

class Shape 
{
public:
    virtual double area() const=0;
};

//三角形
class Triangle : public Shape 
{
private:
    double base, height;
public:
    Triangle(double b,double h) : base(b), height(h) {}
    double area() const;
};

//矩形
class Rectangle : public Shape 
{
private:
    double height, width;
public:
    Rectangle(double h,double w) : height(h), width(w) {}
    double area() const;
};

//圆形
class Circle : public Shape 
{
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double area() const;
};

//函数实现
//三角形
double Triangle::area() const 
{
    return 0.5 * base * height;
}

//矩形
double Rectangle::area() const 
{
    return height * width;
}

//圆形
double Circle::area() const 
{
    return pi * radius * radius;
}

//主函数
int main() 
{
    Shape *ptr[3];
    ptr[0] = new Triangle(2.5, 10);
    ptr[1] = new Rectangle(15, 22);
    ptr[2] = new Circle(3.0);

    cout << "Area of Triangle: " << ptr[0]->area() << endl;
    cout << "Area of Rectangle: " << ptr[1]->area() << endl;
    cout << "Area of Circle: " << ptr[2]->area() << endl;

    delete ptr[0];
    delete ptr[1];
    delete ptr[2];

    return 0;
}
  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tsglz3210

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值