C + + Object Oriented Programming

Posted by d22552000 on Tue, 14 Sep 2021 22:37:50 +0200

C + + object oriented programming (4)

1. Basic concepts of operator overloading

Operator overloading is to give multiple meanings to existing operators (predefined operators in C + +), so that unified operators can lead to different types of behavior when used for different types of data.

The purpose of operator overloading is to expand the scope of use of operators provided in C + + so that they can act on objects.

The same operator behaves differently for different types of operands.

  • Operator overloaded form

The essence of operator overloading is function overloading.

It can be overloaded as a normal function or as a member function.

Converts an expression containing an operator into a call to an operator function.

Converts the operands of an operator to parameters of an operator function.

When the operator is overloaded many times, which operator function to call depends on the type of the argument.

class Complex{
  public:
  double real,imag;
  Complex(double r=0.0,double i=0.0):real(r),imag(i){}
  Complex operator-(const Complex &c);
};
Complex operator+(const Complex &a,const Complex &b){
  return Complex(a.real+b.real,a.imag+b.imag);
}
Complex Complex::operator-(const Complex &c){
  return Complex(real-c.real,imag-c.imag);
}

When overloading is a member function, the number of parameters is the number of operators minus one.

When overloading is a normal function, the number of parameters is the number of operator entries.

int main(){
  Complex a(4,4),b(1,1),c;
  c=a+b;
  //Equivalent to c=operator+(a,b); Ordinary function overloading
  cout<<c.real<<","<<c.imag<<endl;
  cout<<(a-b).real<<","<<(a-b).imag<<endl;
  //a-b is equivalent to a.operator-(b) 	// Member overloading 
  return 0;
}

Exercise:

If the [] operator is overloaded into a member function of a class, how many parameters does the overloaded function have?

(1)

2. Overload of assignment operator

Sometimes you want the types on both sides of the assignment operator to be mismatched. For example, assign an int type variable to a Complex object, or assign a char * type string to a string object. At this time, you need to overload the operator "=".

Assignment operator '=' can only be overloaded as a member function

class String{
  private:
  char *str;
  public:
  String():str(new char[1]){str[0]=0;}
  const char * c_str(){return str;}
  String &operator=(const char *s);
  ~String(){delete [] str};
};
String & String::operator=(const char *s){
  delete [] str;
  str=new char[strlen(s)+1];
  strcpy(str,s);
  return *this;
}
int main(){
  String s;
  s="Good Luck,";
  //Equivalent to s.operator=("Good Luck,");
  cout<<s.c_str()<<endl;
  //String s2="hello!"; This will report an error. This is an initialization statement, not an assignment statement. The initialization statement uses a constructor, because we don't write such a constructor, an error will be reported.
  s="SHenzhou 8!";
  //Equivalent to s.operator=("Shen zhou 8!");
  cout<<s.c_str()<<endl;
  return 0;
}
  • Light copy and deep copy
class String{
  private:
  cahr *str;
  public:
  String():str(new char[1]){str[0]=0;}
  const char * c_str(){return str;};
  String &operator=(const cahr *s){
    delete[] str;
    str=new char[strlen(s)+1];
    strcpy(str,s);
    return *this;
  };
  ~String(){delete[]str;}
};
String s1="this";
String s2="that";
s1=s2;

If you do not define your own assignment operator, s1=s2 actually causes s1.str and s2.str to point to the same place

If the S1 object dies, the destructor will release the space pointed to by s1.str, and it is inappropriate to release it again when s2 dies.

In addition, if s1 = "other" is executed; It will cause the place pointed by s2.str to be delete d

Therefore, add a new member function in class String:

String &operator=(const String&s){
  delete[] str;
  str=new char[strlen(s.str)+1];
  strcpy(str,s.str);
  return *this;
}

The above functions still need to be improved

String s;
s="hello";
s=s;

During the = operation, the memory pointed to by the str member of s is delete d first, resulting in a problem

String &operator=(const Sting&s){
  if(this==&s)
    return *this;
  str=new char[strlen(s.str)+1];
  strcpy(str,s.str);
  return *this;
}

Discussion on operator = return value type

When overloading operators, a good style is to keep the original characteristics of the original operator as much as possible.

Consider a=b=c; (a=b)=c;

Equivalent to:

a.operator=(b.operator=©);

(a.oprator=(b)).operator=©;

When writing a copy constructor for a String class, you will face the same problem as = and handle it in the same way.

When copying, the default copy constructor is called, which only copies str, that is, points to the same place, which will cause problems during destruct.

String(String & s){
  str=new char[strlen(s.str)+1];
  strcpy(str,s.str);
}

Be sure to pay attention to the replication of pointer variables.

3. Operator overloading is a friend function

In general, overloading operators into member functions of classes is a better choice.

However, sometimes, overloaded member functions can not meet the use requirements, overloaded ordinary functions, and can not access the private members of the class, so operators need to be overloaded as friends.

class Complex{
  double:real,imag;
  public:
  Complex(double x,double y):real(r),imag(i){};
  Complex operator+(double r);
};
Complex Complex::operator+(double r){
  return Complex(real+r,img);
}

Complex c;

c=c+5; Defined, equivalent to c.operator+(5);

c=5+c; Will go wrong

Therefore, in order to make the above expression true, you need to overload + as an ordinary function.

Complex operator+(double r,const Complex &c){
  return Complex(c.real+r,c.imag);
}//However, ordinary functions cannot access private members, so you need to overload the operator + as a friend.
class Complex{
  double real,imag;
  public:
  Complex(double r,double i):real(r),imag(i){};
  Complex operator+(double r);
  friend Complex operator+(double r,const Complex &c);
};

4. Variable length array

The following operations can be realized:

int main(){
  CArray a;
  for(int i=0;i<5;++i)
    a.push_back(i);//To store array elements in dynamically allocated memory, you need a pointer member variable
  CArray a2,a3;
  a2=a;//Overload required=
  for(int i=0;i<a.length();++i)
    cout<<a2[i]<<" ";//Overload required []
  a2=a3;
  for(int i=0;i<a2.length();++i)
    cout<<a2[i]<<" ";
  cout<<endl;
  a[3]=100;
  CArray a4(a);//You need to complete the copy constructor to realize deep copy
  for(int i=0;i<a4.length();++i)
    cout<<a4[i]<<" ";
  return 0;
}
class CArray{
  int size;
  int *ptr;
  public:
  CArray (int s=0);
  CArray(CArray & a);
  ~CArray();
  void push_back(int v);
  CArray &operator =(const CArray &a);
  int length(){return size;}
  int &CArray::operator[](int i){//The return value cannot be int. if it is only int, the statement a[i]=4 cannot be implemented. Only the return value referenced as a function can be placed on the left side of the assignment number.
    return ptr[i];
  }
}
CArray::CArray(int s):size(s){
  if(s==0)
    ptr=NULL;
  else
    ptr=new int [s];
}
CArray::CArray(CArray &a){
  if(!a.ptr){
    ptr=NULL;
    size=0;
    return;
  }
  ptr=new int [a.size];
  memcpy(ptr,a.ptr,sizeof(int)*a.size);
  size=a.size;
}
CArray::~CArray(){
  if(!ptr) delete [] ptr;
}
CArray & CArray::operator=(const CArray&a){
  if(ptr==a.ptr)
    return *this;
  if(a.ptr==NULL){
    if(ptr) delete [] ptr;
    ptr=NULL;
    size=0;
    return *this;
  }
  if(size<a.size){
    if(ptr)
      delete [] ptr;
    ptr=new int [a.size];
  }
  memcpy(ptr,a.ptr,sizeof(int)*a.size);
  size=a.size;
  return *this;
}
void CArray::push_back(int v){
  if(ptr){
    int *tmpPtr=new int [size+1];
    memcpy(tmpPtr,ptr,sizeof(int)*a.size);
  	delete [] ptr;
    ptr=tmpPtr;
  }
  else
    ptr=new int[1];
  ptr[size++]=v;
}

Exercise:

What operators are overloaded or what member functions are written in the variable length array class

A) = , [] , ++

B) =, [], copy constructor

C) =, [], + +, copy constructor

D) =, [], &, copy constructor

5. Overloading of stream insertion operator and stream extraction operator

cout is an object of ostream class defined in iostream

< < can act on cout because < < is overloaded in iostream

Cout < < 5, i.e. cout.operator < < (5);

Cout < < this "means cout.operator < < (" this ");

How to cout < < 5 < < this "

ostream & ostream::operator<<(int n){
  return *this;
}
ostream & ostream::operator<<(const char * s){
  return *this;
}

cout<<5<<"this"

Essentially, the call form is as follows:

cout.operator<<(5).operator<<("this");

class CStudent{
  public:
  int nAge;
};
int main(){
  CStudent s;
  s.nAge=5;
  cout<<s<<"hello";//Overload < < so that it can receive object parameters
  return 0;
}
ostream & operator(ostream & o,const CStudent &s){
  o<<s.nAge;
}

Example:

Assuming that C is an object of Complex complex type, if you want to write cout < < C, you can output the value of C in the form of a+bi. If you write CIN > > C, you can receive the input in the form of a+bi from the keyboard and make c.real = a and c.imag = B.

int main(){
  Complex c;
  int n;
  cin>>c>>n;
  cout<<c<<","<<n;
  return 0;
}
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Complex{
  double real,imag;
  public:
  Complex(double r=0,double i=0):real(r),imag(i){};
  friend ostream &operator<<(ostream &os,const Complex &c);
  friend istream &operator>>(istream &is,Complex &c);
};
ostream & operator<<(ostream &os,const Complex &c){
  os<<c.real<<"+"<<c.imag<<"i";
  return os;
}
istream & operator>>(istream &is,Complex &c){
  string s;
  is>>s;
  int pos=s.find("+",0);//Separating real and imaginary parts
  string sTmp=s.substr(0,pos);
  c.real=atof(sTmp.c_str());
  sTmp=s.substr(pos+1,s.length()-pos-2);//
  c.imag=atof(sTmp.c_str());
  return is;
}

Exercise:

When overloading "< <" to output custom objects through cout, which of the following statements is correct? (C)

A) "< <" can be overloaded as a member function of ostream class, and the return value type is ostream&

B) "< <" can be overloaded as a global function. The first parameter and return value are of type ostream

C) "< <" can be overloaded as a global function, and the first parameter and return value are ostream & (correct)

D) "< <" can be overloaded as a member function of ostream class, and the return value type is ostream

6. Overload type conversion operator

#include <iostream>
using namespace std;
class Complex{
  double real,imag;
  public:
  Complex(double r=0,double i=0):real(r),imag(i){};
  operator double(){return real;}
  //Overload cast operator
};
int main(){
  Complex c(1.2,3.4);
  cout<<(double)c<<endl;
  double n=2+C;//double n=2+c.operator double()
  cout<<n;
  return 0;
}

Topics: C++