多态:多种形态

C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。实现多肽的方法有二:

  1. 重载
    在编译的阶段实现多肽
  2. 虚函数
    在程序运行的时候呈现多态性

重载函数

在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。这个非常简单 我就不赘述了。
例子:

#include <iostream>
using namespace std;
 
class printData
{
   public:
      void print(int i) {
        cout << "整数为: " << i << endl;
      }
 
      void print(double  f) {
        cout << "浮点数为: " << f << endl;
      }
 
      void print(char c[]) {
        cout << "字符串为: " << c << endl;
      }
};
 
int main(void)
{
   printData pd;
 
   // 输出整数
   pd.print(5);
   // 输出浮点数
   pd.print(500.263);
   // 输出字符串
   char c[] = "Hello C++";
   pd.print(c);
 
   return 0;
}

重载运算符是特殊的重载函数

我们可以重定义或重载大部分 C++ 内置的运算符。重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。

重载语法

<返回类型> operator <重载符号> (<参数>)
{<函数体>}

  1. 我们可以重载几乎所有c++里面使用过的运算符,但是不能自己定义运算符。

  2. 重载之后,并不改变他的优先级和结合行

  3. 重载虽然可以自己定义他的功能,但是我们要求和原有功能类似

不可以重载的运算符

  1. .:成员访问运算符
  2. ., ->:成员指针访问运算符
  3. :::域运算符
  4. sizeof:长度运算符
  5. ?::条件运算符
  6. #: 预处理符号

我们分类讨论不同的符号有不同的情况,我们这里展开说一下

用成员函数重载符号

这里遇到一个问题,我们的成员函数都会有一个this指针(this指针什么?,可以看这里),所以 当我们的参数是该类的对象时

  • 一元运算符 (‘++’ ‘- -’之类的 ),我们无需在传入参数,用自带的this就好了,这使得我们一元的运算符重载一般都是成员函数
  • 二元运算符: 我们原本要传入两个参数,但是我们现在一个默认自带的this指针所以可以少一个参数哇

友元的方式重载符号

友元的方式重载符号是非常便利的,比成员函数重载更加灵活,就比如说:

当2个对象相加时是没有顺序要求的,但是用成员函数重载 + ,因为我们调用的时候都是通过对象去调用的,则这样让其与一个数字相加则有顺序要求,可以通过加一个友元函数使另一个顺序的输入更加合理。(理解就好)

所以非单目运算符我们大多数用,友元的方式去重载
由于友元函数不属于任何类,那么就没有this指针了,这样就和我们重载一般函数一样了,要求几个参数,就传入几个参数。

常用符号重载注意事项

对a++ ,++a 的重载

看似他们两是一个运算符,但是实则不是,a++ 是先调用a 再去做自加;a反之。所以我们在重载的时候就要区别开来他们。
下面的例子:
myTime operator
(); //前 a
myTime operator
(int); //后a++

#include <iostream>

class myTime
{
public:
    myTime(int x=0,int y=0,int z=0)
    {
    h=x;m=y;s=z;
    if(checktime()) h=m=s=0;
    }
    friend std::istream &operator>>(std::istream &,myTime&);
    friend std::ostream &operator<<(std::ostream &,myTime&);
    myTime operator++();    //前 ++a
    myTime operator++(int); //后a++
    myTime operator--();
    myTime operator--(int);
private:
    int h, m, s;
    bool checktime()
    {
        if(h<0||h>24||m<0||m>64||s<0||s>64)
        {
            std::cout<<"错误,数据非法"<<std::endl;
            return 1;
        }
        return 0;
        
    }
};
std::istream &operator>>(std::istream& in,myTime& t)
{
    in>>t.h;
    in>>t.m;
    in>>t.s;
    while(t.checktime())
    {
        std::cout<<"请重新输入\n";
        in>>t.h>>t.m>>t.s;
    }
    return in;
}
std::ostream &operator<<(std::ostream &out,myTime& t)
{
    std::cout<<t.h<<':'<<t.m<<':'<<t.s;
    return out;
}
myTime myTime::operator++()
{
    h++;
    if(checktime()) h=24;
   return *this; 
}
myTime myTime::operator++(int)
{
    myTime t(*this);
    h++;
    if(checktime()) h=24;
   return t; 
}
myTime myTime::operator--()
{
    h--;
    if(checktime()) h=0;
   return *this; 
}
myTime myTime::operator--(int)
{
    myTime t(*this);
    h--;
    if(checktime()) h=0;
   return t; 
}
int main()
{
    myTime x;
    std::cin>>x;
    std::cout<<x;
    for(int i=1;i<25;i++)
    {
        x++;
        std::cout<<x;
    }
    return 0;
}

赋值运算符 =

我们之前提到,当我们用 ClassA a=b;的时候,系统会自动帮我们调用浅拷贝构造函数,这实现的背后就是对‘=’的重载,所谓浅拷贝构造函数遇到有指针的情况就不大行了,所以我们要重载一下 = 去深拷贝 我们的对象。

对输入输出运算符的重载

C++ 能够使用流提取运算符 >> 和流插入运算符 << 来输入和输出内置的数据类型。我们可以重载流提取运算符和流插入运算符来操作对象等用户自定义的数据类型。 在这里,有一点很重要,我们需要把运算符重载函数声明为类的友元函数,这样我们就能不用创建对象而直接调用函数。

下面的实例演示了如何重载提取运算符 >> 和插入运算符 <<。

#include <iostream>
using namespace std;
 
class Distance
{
   private:
      int feet;             // 0 到无穷
      int inches;           // 0 到 12
   public:
      // 所需的构造函数
      Distance(){
         feet = 0;
         inches = 0;
      }
      Distance(int f, int i){
         feet = f;
         inches = i;
      }
//重载 <<
      friend ostream &operator<<( ostream &output, 
                                       const Distance &D )
      { 
         output << "F : " << D.feet << " I : " << D.inches;
         return output;            
      }
 
      friend istream &operator>>( istream  &input, Distance &D )
      { 
         input >> D.feet >> D.inches;
         return input;            
      }
};
int main()
{
   Distance D1(11, 10), D2(5, 11), D3;
 
   cout << "Enter the value of object : " << endl;
   cin >> D3;
   cout << "First Distance : " << D1 << endl;
   cout << "Second Distance :" << D2 << endl;
   cout << "Third Distance :" << D3 << endl;
 
 
   return 0;
}

结语

其实还有许多重载符号没有写,其实我们做到举一反三即可,到时候遇到啥问题,我在回来继续补充。

在放一个实例在这里
对 类string的扩充

#include<iostream>
#include<string.h>

class myString
{
protected:
char* s;
int len;
public:
myString()
{
    len=0;
    s=new char[len+1];
    s[0]='\0';
    
}
myString(const char* str,int l)
{
    s=new char[len+1];
    strcpy(s,str);
}
~myString()
{
    delete[] s;
}
myString& operator=(const myString& str)
{
    if(*this==str)
    return *this;
    else
    {
        delete[] s;
        len=str.len;
        s=new char[len+1];
        strcpy(s,str.s);
        return *this;
    }
}
// 符号重载 
friend std::ostream &operator<<(std::ostream &out, const myString &str);
friend std::istream &operator>>(std::istream &in, myString &str);
friend myString operator +(const myString& s1,const myString& s2);
friend myString operator +=(myString& s1,const myString& s2);
friend bool operator ==(const myString&,const myString&);
friend bool operator !=(const myString&,const myString&);
};

std::ostream &operator<<(std::ostream &out, const myString &str)
{
    out<<str.s;
    return out;
}

std::istream &operator>>(std::istream &in, myString &str)
{
    in>>str.s;
    str.len=strlen(str.s);
    return in;
}
myString operator +(const myString& s1,const myString& s2)
{
    myString str;
    delete[] str.s;
    str.len=s1.len+s2.len;
    str.s= new char[str.len+1];
    strcat(str.s,s1.s);
    strcat(str.s,s2.s);
    return str;
}
bool operator ==(const myString& s1,const myString& s2)
{
    return !strcmp(s1.s,s2.s);
}
bool operator !=(const myString& s1,const myString& s2)
{
    return strcmp(s1.s,s2.s);
}


int main()
{
    myString s1,s2;
    std::cout<<"请输入两个字符串\n";
    
    std::cin>>s1>>s2;
    std::cout<<"s1: "<<s1<<"\n s2: "<<s2
            <<"\ns1+s2:"<<s1+s2<<std::endl;
    std::cout<<"s1+=s2"<<s1
            <<"\ns1==s2:  "<<int(s1==s2)
            <<"\ns1!=s2:  "<<int(s1!=s2)<<"\n";
    return 0;
}

努力成长的程序员