C++运算符重载

  • 在C语言中,运算符已经被重载(*表示乘法和解引用)
  • C++将运算符重载扩展到自定义的数据类型。
  • 给运算符赋予新的含义,让对象操作更美观(简单易用)

例如:导演要求:每轮表演之后,给超女加上她的得分
首先我们用C和友元类的方法实现

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
class CGirl {
	friend void addscore(CGirl& g, int score);
private:
	int m_xw;//胸围
	int m_score;//分数
public:
	string m_name;//姓名

	CGirl() { m_name = "西施";m_xw = 87;m_score = 30; }
	void show() { cout << "姓名:" << m_name << ",胸围:" << m_xw << ",评分:" << m_score; }
};
void addscore(CGirl& g, int score) {
	g.m_score = g.m_score + score;
}
int main() {
	//导演要求:每轮表演之后,给超女加上她的得分
	CGirl g;
	addscore(g, 30);
	g.show();
}

但是现在C++有更好的方法:

我们定义这个函数 operator+(CGirl& g, int score),这里也弄成友元类
然后我们就可以g+30;

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
class CGirl {
	friend void operator+(CGirl& g, int score);
private:
	int m_xw;//胸围
	int m_score;//分数
public:
	string m_name;//姓名

	CGirl() { m_name = "西施";m_xw = 87;m_score = 30; }
	void show() { cout << "姓名:" << m_name << ",胸围:" << m_xw << ",评分:" << m_score; }
};
void operator+(CGirl& g, int score) {
	g.m_score = g.m_score + score;
}
int main() {
	//导演要求:每轮表演之后,给超女加上她的得分
	CGirl g;
	//operator+(g, 30);
	g + 30;
	g.show();
}

运算符重载基础

C++将运算符重载扩展到自定义的数据类型,它可以让对象操作更美观。
例如字符串string用加号(+)拼接、cout用两个左尖括号(<<)输出。
运算符重载函数的语法: 返回值 operator(参数列表);
运算符重载函数的返回值类型要与运算符本身的含义一致。

  1. 非成员函数版本的重载运算符函数: 形参个数与运算符的操作数个数相同;
  2. 成员函数版本的重载运算符函数: 形参个数比运算符的操作数个数少一个,其中的一个操作数隐式传递了调用对象。

例如:非成员函数版本

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
class CGirl {
	friend void operator+(CGirl& g, int score);
	friend CGirl& operator-(CGirl& g, int score);
private:
	int m_xw;//胸围
	int m_score;//分数
public:
	string m_name;//姓名

	CGirl() { m_name = "西施";m_xw = 87;m_score = 30; }
	void show() { cout << "姓名:" << m_name << ",胸围:" << m_xw << ",评分:" << m_score; }
};
void operator+(CGirl& g, int score) {
	g.m_score = g.m_score + score;
}
CGirl& operator-(CGirl& g, int score) {//因为我们要返回连续减号,所以返回的得是一个超女类型
	g.m_score = g.m_score + score;
	return g;
}
int main() {
	//导演要求:每轮表演之后,给超女加上她的得分
	CGirl g;
	//operator+(g, 30);
	g + 30;
	g.show();
	g=g - 10 - 3 - 4;//函数的多次调用g = operator-(operator-(operator-(g, 20),5),3);
	g.show();
}

成员函数版本

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
class CGirl {
private:
	int m_xw;//胸围
	int m_score;//分数
public:
	string m_name;//姓名

	CGirl() { m_name = "西施";m_xw = 87;m_score = 30; }
	void show() { cout << "姓名:" << m_name << ",胸围:" << m_xw << ",评分:" << m_score; }
	CGirl& operator-( int score) {
		m_score = m_score + score;
		return *this;
	}
};
int main() {
	//导演要求:每轮表演之后,给超女加上她的得分
	CGirl g;
	//operator+(g, 30);
	
	g.show();
	g=g - 10 - 3 - 4;
	g.show();
}

注意:

  1. 返回自定义数据类型的引用可以让多个运算符表达式串联起来。(不要返回局部变量的引用)
  2. 重载函数参数列表中顺序决定了操作数的位置(如果说我们想实现g=4+4+g),那我们的函数得是这样的CGirl& operator+(CGirl& g,int score) ,就是调换一下函数形参的位置,但是对于这种g=g+g,我们需要实现一个CGirl& operator+(CGirl& g1,CGirl& g2)
  3. 重载函数的参数列表中至少有一个是用户自定义的类型,防止程序员为内置数据类型重载运算符。
  4. 如果运算符重载既可以是成员函数也可以是全局函数,应该优先考虑成员函数,这样更符合运算符重载的初衷。
  5. 重载函数不能违背运算符原来的含义和优先级。
  6. 不能创建新的运算符。
  7. 有一些运算符不可重载(自行百度)
  8. 以下运算符只能通过成员函数进行重载:
    = 赋值运算符
    () 函数调用运算符
    [] 下标运算符
    -> 通过指针访问类成员的运算符

常见运算符的重载

  • 关系运算符
  • 左移运算符
  • 下标运算符
  • 赋值运算符
  • new&delete运算符
  • 括号运算符
  • 一元运算符

关系运算符

重载关系运算符(==、!=、>、>=、<、<=)用于比较两个自定义数据类型的大小。
可以使用非成员函数和成员函数两种版本,建议采用成员函数版本。

示例:

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
class CGirl {
public:
	string m_name;//姓名
	int m_yz;//颜值:1-千年美人;2-百年美人;3-绝代美人;4-极漂亮;5-漂亮;6-一般;7-歪瓜裂枣。
	int m_sc;//身材:1-...;2-.….;3-...;4-...; 5-...;6-...;7-膘肥体壮。
	int m_acting;//演技:1-...;2-...; 3-...;4-...; 5-...;6-...;7-四不像。
public:
	CGirl(string name, int yz, int sc, int acting) {
		m_name = name;
		m_yz = yz;
		m_sc = sc;
		m_acting = acting;
	}
	//比较两个超女的商业价值
	bool operator==(const CGirl& g1) {//等于
		if ((m_acting + m_yz + m_sc) == (g1.m_acting + g1.m_yz + g1.m_sc)) return true;

		return false;
	}
	bool operator>(const CGirl& g1) {//大于>
		if ((m_acting + m_yz + m_sc) < (g1.m_acting + g1.m_yz + g1.m_sc)) return true;

		return false;
	}
	bool operator<(const CGirl & g1) {
		if ((m_acting + m_yz + m_sc) > (g1.m_acting + g1.m_yz + g1.m_sc)) return true;

		return false;
	}
};
int main() {
	CGirl g1("西施",1,2, 3), g2("冰冰",3, 2,1);
	if (g1 == g2) {
		cout << "西施和冰冰的商业价值相同.\n";
	}
	else if (g1 > g2) {
		cout << "西施比冰冰的商业价值大.\n";
	}
	else {
		cout << "西施比冰冰的商业价值小.\n";
	}

	
	
}

重载左移运算符

重载左移运算符(<<)用于输出自定义对象的成员变量,在实际开发中很有价值(调试和日志)。
只能使用非成员函数版本。
如果要输出对象的私有成员,可以配合友元一起使用。
例如:
我们创建一个类,然后实例化它,但是我们直接输出这个对象是会报错的

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
class CGirl {
public:
	string m_name;//姓名
	int m_xw;//胸围
	int m_score;//评分
public:
	CGirl() {
		m_name = "西施";
		m_xw = 87;
		m_score = 30;
	}
	//比较两个超女的商业价值
	void show() {
		cout << "姓名:" << m_name << ",胸围:" << m_xw << ",评分:" << m_score << endl;
	}
};
int main() {
	CGirl g;
	cout << g << endl;

	
	
}

这个时候我们可以重载cout

ostream& operator<<(ostream& cout, const CGirl& g) {
	cout << "姓名:" << g.m_name << ",胸围:" << g.m_xw << ",评分:" << g.m_score << endl;
	return cout;
}
#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
class CGirl {
public:
	string m_name;//姓名
	int m_xw;//胸围
	int m_score;//评分
public:
	CGirl() {
		m_name = "西施";
		m_xw = 87;
		m_score = 30;
	}
	//比较两个超女的商业价值
	void show() {
		cout << "姓名:" << m_name << ",胸围:" << m_xw << ",评分:" << m_score << endl;
	}
};
ostream& operator<<(ostream& cout, const CGirl& g) {
	cout << "姓名:" << g.m_name << ",胸围:" << g.m_xw << ",评分:" << g.m_score << endl;
	return cout;
}
int main() {
	CGirl g;
	cout << g << endl;

	
	
}

但是要注意重载左移运算符,只能再类外

重载下标运算符

如果对象中有数组,重载下标运算符[],操作对象中的数组将像操作普通数组一样方便。
下标运算符必须以成员函数的形式进行重载。
下标运算符重载函数的语法:
返回值类型 &perator[](参数);
或者
const 返回值类型 &perator[](参数) const;
使用第一种声明方式,[]不仅可以访问数组元素,还可以修改数组元素。
使用第二种声明方式,[]只能访问而不能修改数组元素。
在实际开发中,我们应该同时提供以上两种形式,这样做是为了适应const对象,因为通过const对象只能调用const成员函数,如果不提供第二种形式,那么将无法访问const对象的任何数组元素。

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
class CGirl {
private:
	string m_boys[3];//超女男朋友
public:
	string m_name;
	CGirl() {
		m_boys[0] = "子都";
		m_boys[1] = "潘安";
		m_boys[2] = "宋玉";
	}
	//比较两个超女的商业价值
	void show() {
		cout << m_boys[0] << "、" << m_boys[1] << "、" << m_boys[2] << endl;
	}
	string& boys(int ii) {
		return m_boys[ii];
	}
	string& operator[](int ii) {
		return m_boys[ii];
	}
	const string& operator[](int ii) const {
		return m_boys[ii];
	}
};
int main() {
	CGirl g;
	g[1] = "王麻子";
	cout << "第一任男朋友:" << g[1]<< endl;
	g.show();
	const CGirl g1 = g;
	cout << "第一任男朋友:" << g1[1] << endl;
	
	
}


重载复制运算符

C++编译器可能会给类添加四个函数:

  • 默认构造函数,空实现。
  • 默认析构函数,空实现。
  • 默认拷贝构造函数,对成员变量进行浅拷贝。
  • 默认赋值函数,对成员变量进行浅拷贝。
    对象的赋值运算是用一个已经存在的对象,给另一个已经存在的对象赋值。
    如果类的定义中没有重载赋值函数,编译器就会提供一个默认赋值函数。
    如果类中重载了赋值函数,编译器将不提供默认赋值函数。
    重载赋值函数的语法:类名& operator=(const 类名 & 源对象);
#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
class CGirl {
public:
	int m_bh;
	string m_name;
	void show() {
		cout << "编号:" << m_bh << ",姓名" << m_name << endl;
	}
	CGirl& operator=(const CGirl& g) {
		if (this == &g) return *this;
		this->m_bh = g.m_bh;
		this->m_name = g.m_name;
		cout << "调用了重载复制函数" << endl;
		return *this;
	}
};
int main() {
	CGirl g1,g2;
	g1.m_bh = 8;g1.m_name = "西施";
	g1.show();
	g2.show();
	g2 = g1;
	g2.show();
	return 0;
}


注意:

  • 编译器提供的默认赋值函数,是浅拷贝。
  • 如果对象中不存在堆区内存空间,默认赋值函数可以满足需求,否则需要深拷贝。
  • 赋值运算和拷贝构造不同:拷贝构造是指原来的对象不存在,用已存在的对象进行构造;赋值运算是指已经存在了两个对象,把其中一个对象的成员变量的值赋给另一个对象的成员变量。

重载new&delete运算符

重载new和delete运算符的目是为了自定义内存分配的细节。(内存池:快速分配和归还,无碎片)
建议先学习C语言的内存管理函数malloc()free()
在C++中,使用new时,编译器做了两件事情:

  1. 调用标准库函数operator new()分配内存;
  2. 调用构造函数初始化内存;

使用delete时,也做了两件事情:

  1. 调用析构函数;
  2. 调用标准库函数operator delete()释放内存。

构造函数和析构函数由编译器的调用,我们无法控制。
但是,可以重载内存分配函数operator new()和释放函数operator delete()

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
void* operator new(size_t size) {//参数必须是size_t(unsigne long long ),返回值必须是void*.
	cout << "调用了重载的new:" << size << "字节。\n";
	void* ptr = malloc(size);//申请内存
	cout << "申请到的内存的地址是:" << ptr << endl;
	return ptr;//返回起始地址
}
void operator delete(void* ptr) {//参数必须是void* ,返回void
	cout << "调用了重载的delete。\n";
	if (ptr == 0) return;//对空指针delete是安全的
	free(ptr);//释放内存
}
class CGirl {
public:
	int m_bh;
	int m_xw;
	CGirl(int bh, int xw) {
		m_bh = bh;
		m_xw = xw;
		cout << "调用了构造函数CGirl"<<endl;
	}
	~CGirl()
	{
		cout << "调用了析构函数~CGirl" << endl;
	}
};
int main() {
	int* p1 = new int(3);
	cout << "p1=" << (void*)p1 << ",*p1=" << *p1 << endl;
	delete p1;

	CGirl* p2 = new CGirl(3, 8);
	cout << "p2的地址是:" << p1 << "编号:" << p2->m_bh << ",胸围:" << p2->m_xw << endl;
	delete p2;
	return 0;
}

内存池

  • 预先分配一大块的内存空间。
  • 提升分配和归还的速度。
  • 减少内存碎片。

例如:
在这里插入图片描述
这个占用的是八字节的内存。我们打算向系统申请连续的18字节内存空间。
在这里插入图片描述
其中:

前两个是标识位,1字节,表示后面的空间是否被占用。每个后面正好8字节,存放一个超女类,标志位的取值只有0和1,0表示空闲,1表示占有。这样的话,这18个字节的内存池只能存放两个超女对象。当需要为超女对象分配内存的时候,先判断标志位是否被占用。如果没有被占用。就把标志脑局面这个肉存的地返回。
代码:

#include <iostream>         // 包含头文件。
#include<stdio.h>
#include<cstring>
using namespace std;        // 指定缺省的命名空间。
                  
class CGirl       // 超女类CGirl。
{
public:
  int        m_bh;               // 编号。
  int        m_xw;              
  static char*    m_pool;           // 内存池的起始地址。
                 
  static bool initpool()             // 个初始化内存池的函数。
  {
    m_pool = (char*)malloc(18);           // 向系统申请18字节的内存。
    if (m_pool == 0)  return false;        // 如果申请内存失败,返回false。
    memset(m_pool, 0, 18);                  // 把内存池中的内容初始化为0。
    cout << "内存池的起始地址是:" << (void*)m_pool << endl;
    return true;
  }
               
  static void freepool()                                     // 释放内存池。
  {
    if (m_pool == 0) return;                  // 如果内存池为空,不需要释放,直接返回。
    free(m_pool);                                        // 把内存池归还给系统。
    cout << "内存池已释放。\n";
  }
               
  CGirl(int bh, int xw) { m_bh = bh, m_xw = xw;  cout << "调用了构造函数CGirl()\n"; }
  ~CGirl() { cout << "调用了析构函数~CGirl()\n"; }
             
  void* operator new(size_t size)   // 参数必须是size_t(unsigned long long),返回值必须是void*。
  {
    if (m_pool[0] == 0)      // 判断第一个位置是否空闲。
    {
      cout << "分配了第一块内存:" << (void*)(m_pool + 1) << endl;
      m_pool[0] = 1;         // 把第一个位置标记为已分配。
      return m_pool + 1;  // 返回第一个用于存放对象的址。
    }
    if (m_pool[9] == 0)          // 判断第二个位置是否空闲。
    {
      cout << "分配了第二块内存:" << (void*)(m_pool + 9) << endl;
      m_pool[9] = 1;             // 把第二个位置标记为已分配。
      return m_pool + 9;      // 返回第二个用于存放对象的址。
    }
    
    // 如果以上两个位置都不可用,那就直接系统申请内存。
    void* ptr = malloc(size);        // 申请内存。
    cout << "申请到的内存的地址是:" << ptr << endl;
    return ptr;
  }
              
  void operator delete(void* ptr)   // 参数必须是void *,返回值必须是void。
  {
    if (ptr == 0) return;      // 如果传进来的地址为空,直接返回。
                
    if (ptr == m_pool + 1)      // 如果传进来的地址是内存池的第一个位置。
    {
      cout << "释放了第一块内存。\n";
      m_pool[0] = 0;              // 把第一个位置标记为空闲。
      return;
    }
                
    if (ptr == m_pool + 9)      // 如果传进来的地址是内存池的第二个位置。
    {
      cout << "释放了第二块内存。\n";
      m_pool[9] = 0;              // 把第二个位置标记为空闲。
      return;
    }
                 
    // 如果传进来的地址不属于内存池,把它归还给系统。
    free(ptr);      // 释放内存。
  }
};
                      
char* CGirl::m_pool = 0;       // 初始化内存池的指针。
                  
int main()
{           
  // 初始化内存池。
  if (CGirl::initpool()==false) { cout << "初始化内存池失败。\n"; return -1; }

  CGirl* p1 = new CGirl(3, 8);       // 将使用内存池的第一个位置。
  cout << "p1的地址是:" << p1 << ",编号:" << p1->m_bh << ",数据:" << p1->m_xw << endl;
                  
  CGirl* p2 = new CGirl(4, 7);       // 将使用内存池的第二个位置。
  cout << "p2的地址是:" << p2 << ",编号:" << p2->m_bh << ",数据:" << p2->m_xw << endl;
                    
  CGirl* p3 = new CGirl(6, 9);       // 将使用系统的内存。
  cout << "p3的地址是:" << p3 << ",编号:" << p3->m_bh << ",数据:" << p3->m_xw << endl;
                 
  delete p1;    // 将释放内存池的第一个位置。
                 
  CGirl* p4 = new CGirl(5, 3);        // 将使用内存池的第一个位置。
  cout << "p4的地址是:" << p4 << ",编号:" << p4->m_bh << ",数据:" << p4->m_xw << endl;
        
  delete p2;    // 将释放内存池的第二个位置。
  delete p3;    // 将释放系统的内存。
  delete p4;    // 将释放内存池的第一个位置。
                
  CGirl::freepool();     // 释放内存池。
}

重载括号运算符

括号运算符()也可以重载,对象名可以当成函数来使用(函数对象、仿函数)。
括号运算符重载函数的语法:

返回值类型operator()(参数列表);

注意:

  • 括号运算符必须以成员函数的形式进行重载,不能用全局函数。
  • 括号运算符重载函数具备普通函数全部的特征。
  • 如果函数对象与全局函数同名,按作用域规则选择调用的函数。

函数对象的用途:

  • 表面像函数,部分场景中可以代替函数,在STL中得到广泛的应用;
  • 函数对象本质是类,可以用成员变量存放更多的信息;
  • 函数对象有自己的数据类型;
  • 可以提供继承体系。
#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。
void show(string str)    // 向超女表白的函数。
{
  cout << "普通函数:" << str << endl;
}

class CGirl      
{
public:
  void operator()(string str)    
  {
    cout << "重载函数:" << str << endl;
  }
};

int main()
{
  CGirl show;
  // 这里加了::会优先调用普通函数,否则应该优先调用重载函数
  ::show("我是一只傻傻鸟。");
  show("我是一只傻傻鸟。");
}


重载一元运算符 ++

1)++ 自增 2)-- 自减 3)! 逻辑非 4)& 取地址
5)~ 二进制反码 6)
解引用 7)+ 一元加 8) - 一元求反
*

一元运算符通常出现在它们所操作的对象的左边。
但是,自增运算符++和自减运算符--有前置和后置之分。
C++ 规定,重载++--时,如果重载函数有一个int形参,编译器处理后置表达式时将调用这个重载函数。
语法:

成员函数版:CGirl &operator++();             // ++前置
成员函数版:CGirl operator++(int);            // 后置++
非成员函数版:CGirl &operator++(CGirl &);   // ++前置
非成员函数版:CGirl operator++(CGirl &,int);  // 后置++

在表达式中,前置的自增可以嵌套,但是后置的自增不可以嵌套

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。
                  
class CGirl       // 超女类CGirl。
{
public:
    string m_name;
    int m_ranking;
    CGirl() {
        m_name = "西施";
        m_ranking = 5;
    }
    void show() const{
        cout << "姓名:" << m_name << ",排名:" << m_ranking << endl;
    }
    CGirl& operator++() {
        m_ranking++;
        return *this;
    }
};

                  
int main()
{          
    CGirl g;
    ++(++(++g));
    g.show();
    return 0;
}

自动类型转化

计算机进行运算时,要求各操作数的类型具有相同的大小和存储方式。

在实际开发中,不同类型的数据进行混合运算是基本需求。
自动类型转换:某些类型的转换编译器可以隐式的进行,不需程序员干预。
强制类型转换:有些类型的转换需要程序员显式指定。

  1. 自动类型转化
    不同数据类型的差别在于取值范围和精度,数据的取值范围越大,精度越高。

整型从低到高:
char -> short -> int -> long -> long long
浮点型从低到高:
float -> double -> long double

自动类型转换的规则如下:

  • 如果一个表达式中出现了不同类型操作数的混合运算,较低类型将自动向较高类型转换。
  • 当表达式中含有浮点型操作数时,所有操作数都将转换为浮点型。
  • 赋值运算的右值类型与左值类型不一致时,将右值类型提升/降低为左值类型。
  • 赋值运算右值超出了左值类型的表示范围,把该右值截断后赋给左值,所得结果可能毫无意义。
  1. 强制类型转化
    为了让程序设计更灵活,转换的目的更清晰,C++提供了强制类型转换的方法,也称之为显式转换。
    强制类型转换的语法︰(目标类型)表达式
    注意:
  • 如果使用强制转换,表示程序员已有明确的目的。
  • 如果转换的行为不符合理,后果由程序员承担。
  • 如果采用了强制类型转换,编译的告警信息将不再出现。
  • 类型转换运算符的优先级比较高,如果没把握就加括号。

自动类型转化
对于内置类型,如果两种数据类型是兼容的,C++可以自动转换,如果从更大的数转换为更小的数,可能会被截断或损失精度。

long count=8;//int 转换为long
double time=11//int 转化为double
int side=3.33 //double转化为int的3

C++不自动转化不兼容的类型,下面语句是非法的:

int *ptr=8;

不能自动转化时,可以使用强制类型转化:

int *p=(int*)8;

如果某种类型与类相关,从某种类型转换为类类型是有意义的。
string str ="我是一只傻傻鸟。";
在C++中,一个参数的构造函数为将类型与该参数相同的值转换为类提供了蓝图。这一过程称为隐式转换,它是自动进行的,不需要显示强制类型转换。

CGirl g=CGirl(8);//显示转换
CGirl g=8;//隐式转化
CGirl g;//创建对象
g=8;//用CGirl(8)创建对象,在赋值给g.

注意:

  1. 一个类可以有多个转化函数
  2. 多个参数的构造函数,除第一个参数外,如果其它参数有缺省值,也可以作为转换函数
  3. CGirl(int)的隐式转换的场景:
    • 将CGirl对象初始化为int值时。CGirl g1 = 8;
    • 将int值赋给CGirl对象时。CGirl g1; g1 = 8;
    • 将int值传递给接受CGirl参数的函数时。
    • 返回值被声明为CGirl的函数试图返回int值时。
    • 在上述任意种情况下使用可转换为int类型的内置类型时
  4. 如果自动类型转换有二义性,编译将报错。
    将构造函数用作自动类型转换函数似乎是一项不错的特性,但有时候会导致意外的类型转换。explicit关键字用于关闭这种自动特性,但仍允许显示转换。
explicit CGirl(int bh);
CGirl g=8;//错误。
CGirl g=CGirl(8);//显示转换,可以。
CGirl g=(CGirl)8;//显示转换,可以。

在实际开发中,如果强调的是构造,建议使用explicit,如果强调的是类型转换,则不使用explicit

转换函数

构造函数只用于从某种类型到类类型的转换,如果要进行相反的转换,可以使用特殊的运算符函数-转换函数。
语法:operator 数据类型();

注意:转换函数必须是类的成员函数;不能指定返回值类型;不能有参数。

可以让编译器决定选择转换函数(隐式转换),可以像使用强制类型转换那样使用它们(显式转换)。

int ii=girl;//隐式转化
int ii=(int)girl;//显式转化
int ii=int(girl);//显式转化

如果隐式转换存在二义性,编译器将报错。
在C++98中,关键字explicit不能有于转换函数,但C++11消除了这种限制。因此,在C++11中,可以将转换运算符声明为显式的。
还有一种方法是:用一个功能相同的非转换函数替换转换函数,只要当函数被显式的调用时才会执行。

int ii=girl.to_int();

警告:应谨慎的使用隐式转换函数。通常,最好选择仅在被显式地调用时才会执行的函数。

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。
                  
class CGirl       // 超女类CGirl。
{
public:
    int m_bh;
    string m_name;
    double m_weight;
    CGirl() { m_bh = 8;m_name = "西施";m_weight = 50.7; }
    ~CGirl(){}
    operator int() { return m_bh; };
    operator string() { return m_name; };
    operator double() { return m_weight; };

};

                  
int main()
{
    CGirl g;
    int a = g.to_int();cout << "a的值是:" << a << endl;
    string b = g;cout << "b的值是:" << b << endl;
    double c = g;cout << "c的值是:" << c << endl;
    short d=(int)g;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值