C++:多态性

简介: 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;
}
目录
相关文章
|
1月前
|
设计模式 算法 编译器
C++中的多态性技术
C++中的多态性技术
|
1月前
|
存储 C++
C++中的多态性
C++中的多态性
31 2
|
1月前
|
Serverless C++
C++多态性、虚函数、纯虚函数和抽象类知识网络构造
C++多态性、虚函数、纯虚函数和抽象类知识网络构造
|
1月前
|
编译器 C++
C++程序中的多态性
C++程序中的多态性
7 0
|
1月前
|
C++ 开发者
C++程序中利用虚函数实现动态多态性
C++程序中利用虚函数实现动态多态性
26 2
|
1月前
|
C++
C++|多态性与虚函数(2)|虚析构函数|重载函数|纯虚函数|抽象类
C++|多态性与虚函数(2)|虚析构函数|重载函数|纯虚函数|抽象类
|
1月前
|
存储 安全 C语言
C++|多态性与虚函数(1)功能绑定|向上转换类型|虚函数
C++|多态性与虚函数(1)功能绑定|向上转换类型|虚函数
|
1月前
|
Serverless C++ 容器
【期末不挂科-C++考前速过系列P5】大二C++实验作业-多态性(3道代码题)【解析,注释】
【期末不挂科-C++考前速过系列P5】大二C++实验作业-多态性(3道代码题)【解析,注释】
|
1月前
|
安全 编译器 C++
【C++20概念】编译时多态性的力量
【C++20概念】编译时多态性的力量
59 0
|
1月前
|
算法 编译器 程序员
【C++入门到精通】C++入门 —— 继承(基类、派生类和多态性)
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。
85 0