嵌入式C++开发详解(六)

时间:2021-09-12 17:24:38

运算符重载

一、友元机制

1.友元介绍

·友元是一种允许非类成员函数访问类的非公有成员的一种机制

·可以把一个函数指定为类的友元,也可以把整个类指定为另一个类的友元。

   友元函数

   友元类

2.友元函数

·友元函数在类作用域外定义,但它需要在类体中进行说明

·为了与该类的成员函数加以区别,定义的方式是在类中用关键字friend说明该函数,格式如下:

      friend 类型  友元函数名(参数表)

友元的作用在于提高程序的运行效率

友元函数的注意事项:

·友元函数不是类的成员函数,在函数体中访问对象的成员,必须用对象名加运算符“.”加对象成员名。但友元函数可以访问类中的所有成员(公有的、私有的、保护的),一般函数只能访问类中的公有成员。

·友元函数不受类中的访问权限关键字限制,可以把它放在类的公有、私有、保护部分,但结果一样。

·某类的友元函数的作用域并非该类作用域。如果连友元函数不是另一类的成员函数,则其作用域为另一类的作用域,否则与一般函数相同。

·友元函数破坏了面向对象程序类的封装性,所有友元函数如不是为了必须使用则尽可能少用。或者用其他手段保护封装性。

3.友元类

友元类的注意事项:

·友元关系是单向的

·友元关系不能被传递

·友元关系不能被继承

代码示例:

String.h;
#ifndef _STRING_H_
#define _STRING_H_

class String
{
public:
friend class StringTool;
friend void print(const String &s1); //友元函数
String();
String(char *str);
~String();
void Display();
private:
char *str_;

};
#endif
String.cpp:
#include <iostream>
#include "String.h"

using namespace std;

String::String()
{
cout << "default constructor String!" << endl;
}
String::String(char *str)
{
cout << "constructor String" << endl;
int len = strlen(str) + 1;
str_ = new char(len);
memset(str_, 0, len);
strcpy(str_, str);
}

String :: ~String()
{
cout << "destory String" << endl;
}

void String::Display()
{
cout << str_ << endl;
}

void print(const String& s1)//友元函数
{
cout << s1.str_ << endl;
}

StringTool.h:
#ifndef _STRINGTOOL_H_
#define _STRINGTOOL_H_
#include "String.h"

class StringTool
{
public:
void mystrcat(String& s1, String& s);
};

#endif
StringTool.cpp:
#include <iostream>
#include <string.h>
#include "StringTool.h"

void StringTool::mystrcat(String &s1, String &s)
{
strcat(s1.str_, s.str_);
}

main.c:
#include <iostream>
#include "String.h"
#include "StringTool.h"
using namespace std;

int main()
{
String s1("hello");
print(s1);
//String s2("world");
//StringTool st;
//st.mystrcat(s1, s2);//调用友元类

return 0;
}

运行结果:

嵌入式C++开发详解(六)

二、运算符重载

1.运算符重载介绍

·运算符重载允许把标准运算符(如+*/<>等)应用于自定义数据类型的对象

运算符重载的作用

·直观自然,可以提高程序的可读性

·体现了C++的可扩充性

·运算符重载仅仅只是为了语法上的方便,它是另一种函数调用方式

·运算符重载,本质上是函数重载

运算符重载的注意事项:

·不要滥用重载,本质上是函数重载

2.运算符重载的实现

(1)成员函数重载

  · 成员函数原型格式:

     函数类型 operator 运算符(参数表);

  ·成员函数定义的格式:

     函数类型 类名 :: operator 运算符(参数表)

     {

         函数体;

     }

(2)友元函数重载

  ·友元函数原型的格式:

friend 函数类型 operator运算符(参数表);

  ·友元函数定义的格式:

函数类型 函数类型 类名::operator 运算符(参数表)

{

    函数体;

}

3.运算符重载规则

·运算符重载不允许发明新的运算符

·不能改变运算符操作对象的个数

·运算符被重载后,其优先级和结合性不会改变

·不能被重载的运算符

   作用域解析运算符 ::

   条件运算符   ?:

   直接成员访问运算符   .

   类成员指针引用的运算符 .*

   sizeof运算符     sizeof

·成员函数重载和友元函数重载的选择

  一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函

  数

  以下一些双目运算符不能重载为类的友元函数:= ()、[]、->

  类型转换运算符只能以成员函数方式重载

  流运算符只能以友元的方式重载

 

4.++运算符的重载

(1)成员函数重载方式

(2)友元函数重载方式

代码示例:

Integer.h:
#ifndef _INTEGER_H_
#define _INTEGER_H_

class Integer
{
public:
Integer();
Integer(int n);
~Integer();
void Display() const;
Integer& operator++();
Integer operator++(int n);
// friend Integer& operator++(Integer &i); //友元函数重载方式
// friend Integer operator++(Integer &i,int n); //友元函数重载方式
operator int();
private:
int n_;
};
#endif

Integer.cpp:
#include "Integer.h"
#include <iostream>

using namespace std;

Integer :: Integer()
{

}

Integer :: Integer(int n) : n_(n)
{

}

Integer :: ~Integer()
{

}

void Integer :: Display() const
{
cout << n_ << endl;
}

Integer& Integer :: operator++()
{
cout << "++i" << endl;

++n_;

return *this;
}
Integer Integer :: operator++(int n)
{
cout << "i++" << endl;

Integer tmp(n_);

n_++;

return tmp;
}

#if 0

Integer& operator++(Integer& i)
{
cout << "friend ++i" << endl;
++i.n_;

return i;
}

Integer operator++(Integer& i,int n)
{
cout << "friend i++" << endl;

Integer temp(i.n_);
i.n_++;
return temp;
}

#endif

Integer :: operator int()
{
return n_;
}

Main.c:
#include "Integer.h"
#include <iostream>

using namespace std;

Integer :: Integer()
{

}

Integer :: Integer(int n) : n_(n)
{

}

Integer :: ~Integer()
{

}

void Integer :: Display() const
{
cout << n_ << endl;
}

Integer& Integer :: operator++()
{
cout << "++i" << endl;

++n_;

return *this;
}
Integer Integer :: operator++(int n)
{
cout << "i++" << endl;

Integer tmp(n_);

n_++;

return tmp;
}

#if 0

Integer& operator++(Integer& i)
{
cout << "friend ++i" << endl;
++i.n_;

return i;
}

Integer operator++(Integer& i,int n)
{
cout << "friend i++" << endl;

Integer temp(i.n_);
i.n_++;
return temp;
}

#endif

Integer :: operator int()
{
return n_;
}

运行结果请自行实践~

 

5.!运算符重载

成员函数原型:

   bool operator!() const;

成员函数定义:

   bool String :: operator!()  const

   {

       return strlen(str_)  ! = 0;

   }

6.赋值运算符重载

成员函数原型

String& operator = (const String& other);

成员函数定义:

String& String :: operator = (const String& other)

{

    if(this == &other)

    {

        return * this;

    }

 

    int len = strlen(other.str_) + 1;

 

    delete[] str_;

 

    str_  = new char[len];

    memset(str_,0,len);

    strcpy(str_,other.str_);

}

 

7.[]运算符重载

成员函数原型

(1)char& operator[](unsigned int index);

(2)const char& operator[](unsigned int index) const;

成员函数定义:

(1)char& String :: operator[](unsigned int index)

{

    cout << "no const" << endl;

 

    //return str_[index];

    return const_cast<char&>(static_cast<const String&>(*this)[index]);

}

 

(2)const char& String :: operator[](unsigned int index) const

{

    cout << "const[]" << endl;

 

    return str_[index];

}

8.+运算符重载

成员函数原型

friend String operator+(const String &s1,const String &s2);

成员函数定义:

String operator+(const String& s1,const String& s2)

{

#if 0

    int len = strlen(s1.str_) + strlen(s2.str_) + 1;

    char * newstr = new char[len];

    memset(newstr,0,len);

    strcpy(newstr,s1.str_);

    strcat(newstr,s2.str_);

    String temp(newstr);

 

    delete newstr;

#endif     //实现+=后可以直接使用下面几行代码

 

    String temp(s1);

    temp += s2;

 

    return temp;

 

}

9.+=运算符重载

成员函数原型

String& operator+=(const String& other);

成员函数定义:

String& String :: operator+=(const String& other)

{

    int len = strlen(str_) + strlen(other.str_) + 1;

    char * newstr = new char[len];

    memset(newstr,0,len);

    strcpy(newstr,str_);

    strcat(newstr,other.str_);

    delete[] str_;

    str_ = newstr;

 

    return * this;

}

10.流运算符重载

·为什么一定要使用友元函数进行重载?

如果是重载双目操作符(即为类的成员函数),就只要设置一个参数作为右侧运算量,而左侧运算量就是对象本身

 >> <<左侧运算量是 cincout而不是对象本身,所以不满足后面一点,就只能申明为友元函数了

成员函数原型

(1)friend ostream& operator<<(ostream& out,const String& s);

(2)friend istream& operator>>(istream& in,String& s);

成员函数定义:

(1)ostream& operator<<(ostream& out,const String& s)

{

    out << s.str_;

 

    return out;

}

 

(2)istream& operator>>(istream& in,String& s)

{

    char buffer[1024];

    in >> buffer;

    int len  = strlen(buffer) + 1;

    delete[] s.str_;

    s.str_ = new char[len];

 

    strcpy(s.str_,buffer);

 

    return in;

}

11.类型转换运算符重载

·必须是成员函数,不能是友元函数

·没有参数(操作数是什么?)

·不能指定返回类型(其实已经指定了)

·函数原型:operator 类型名();

Integer :: operator int()

{

    return n_;

}

 

int main(void)

{

Integer n(100);

n = 200;

n.Display();

 

int sum = add(n,100);

cout << sum << endl;

 

int x = n;

int v = static cast<int>(n);

 

return 0;

}

12.->运算符重载

#include <iostream>

using namespace std;

 

class DBHelper

{

public:

  DBHelper()

  {

   cout<<"DB ..."<<endl;

  }

  ~DBHelper()

  {

   cout<<"~DB ..."<<endl;

  }

 

  void Open()

  {

   cout<<"Open ..."<<endl;

  }

 

  void Close()

  {

   cout<<"Close ..."<<endl;

  }

 

  void Query()

  {

   cout<<"Query ..."<<endl;

  }

};

 

class DB

{

public:

  DB()

  {

   db_ = new DBHelper;

  }

 

  ~DB()

  {

   delete db_;

  }

 

  DBHelper* operator->()

  {

   return db_;

  }

private:

  DBHelper* db_;

};

 

 

int main(void)

{

  DB db;

  db->Open();

  db->Query();

  db->Close();

  return 0;

}

13.new/delete

(1)operator new

(1) 只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则 ->如果有new_handler,则调用new_handler,否则

  ->如果没要求不抛出异常(以nothrow参数表达),则执行bad_alloc异常,否则

 ->返回0

(2) 可以被重载

(3) 重载时,返回类型必须声明为void*

(4) 重载时,第一个参数类型必须为表达要求分配空间的大小(字节),类型为size_t

(5) 重载时,可以带其它参数

void * operator new(size_t size)

{

cout <<void * operator new(size_t size size) << endl;

void *p = malloc(size);

return p;

}

void operator delete(void *p)

{

cout <<void operator delete(void *p) << endl;

free(p);

}

(2)new operator

new operator 

1)调用operator new分配足够的空间,并调用相关对象的构造函数 

2)不可以被重载

(3)placement new(不分配内存+构造函数的调用)