【面向对象】重载详解

1. 函数重载

1.1 参数的默认值

  1. C++中带参的函数在声明时,可以给形参赋值作为参数的默认值。当主函数调用该函数时,若传入的参数不足,子函数可以自动将默认参数补齐参数列表,执行子函数;
  2. 默认值是从右到左开始传入,即优先使用传参,若传参用完时才使用默认参数。若使用了一个默认参数,则参数列表中其后的参数都将使用默认参数;
int func1(int a, int b = 5);		//函数的声明,b的默认参数值为5
int func2(int a = 0, int b = 5, int c)//不合法,若传参小于3个,会优先取代a和b的默认值,此时c无默认值,则意味着缺少参数;
int main()
{
	printf("%d\n", func1(10));	//输出值为15
}
int func1(int a, int b)
{
	return a + b;
}
int func2(int a, int b, int c)
{
	return a + b + c;
}

1.2 占位参数

  1. 参数占位就是在参数定义时,参数列表中的只有参数类型而无参数名;
  2. 由于占位参数无参数名,所以函数体内部无法使用占位参数,占位参数是为了兼容C语言;
int func(int a, int )	//第二个参数为占位参数
{
	return a;
}
int main()
{
	printf("%d\n", func(510));	//输出 5
	return 0;
}

1.3 重载函数

1.3.1 函数重载概述

  1. C++中的函数重载就是函数名相同、参数列表不同(参数数量不同/类型不同/顺序不同)、返回值与函数体无关的多个同名函数;
int func()
{
	return 0;
}
char func(int a)				//参数数量不同
{
	return a;
}
double func(int a, char b)		//参数数量不同
{
	printf("%d\n", a);
	printf("%c\n", b);
	return 0.0;
}
float func(char b, int a)		//参数顺序不同
{
	printf("%d\n", a);
 	printf("%c\n", b);
 	return 0.0}
  1. 重载函数匹配的准则
    (1)精确匹配函数名
    (2)在匹配的函数名中,精确匹配参数列表
    (3)当函数指针与重载一起时,会精确匹配函数指针指向的函数类型
    (4)除了通过指针函数重载之外,重载函数与返回值类型无关,只与参数和函数名相关;
double func(int a)			//定义函数
{
	return 5.0;	
}
int func(int a, char b = 0)	//定义重载函数
{
	return 1;
}
int main()
{
	typedef int (*FUNC)(int);	//定义函数指针
	FUNC p = func;			//会报错,因为重载函数类型的候选者中,没有返回值类型可以匹配上函数指针的,所以无法匹配重载函数
	typedef double (*FUNC1)(int);
	FUNC1 p1 = func;			//并不会报错,从函数名到参数列表到返回值类型逐步匹配最终锁定;
	double c = p1(1);
	printf("c = %lf\n", c);		//输出 c = 5.00000000
	return 0;
}
  1. 重载函数之间除了名称相同之外并无其他关系,各个函数之间存储的地址也不同,因此只通过函数名而忽视参数列表来访问该函数,编译器会报错;
int func(int a)				//定义函数
{
	return 0;
}
int func(int a, int b)		//重载函数
{
	return 0;
}
int main()
{
	printf("%p\n", (int (*)(int, int))func);	//打印两个重载函数的地址
	printf("%p\n", (int (*)(int))func);			//输出的结果并不相同,说明重载函数并非同一个函数
	return 0;
}

1.3.2 重载函数的使用

  1. 重载函数与默认参数
    当重载函数的参数中有默认参数时,则无法确认调用的是哪个参数时,就会报错;
int func(int a, int b = 5)		//函数含有默认参数
{
	return a + b;
}
int func(int a)					//重载函数
{
	return a;
}
int main(int argc, char **argv)
{
	int n = func(1);	//编译器会报错,因为两个函数都可以传入这个参数,无法确认调用的时哪个函数
	printf("%d\n", n);
}
  1. 函数功能的扩展
    通过相同名称而不同参数,来扩展同名函数的功能,本质上是不同函数,但使用时可能通过名字可知功能上的类似;
/*
*strcpy函数可以用来赋值字符串,但无法限制赋值的长度
*strncpy函数可以通过设置来限制赋值字符串的长度
*可以通过重载函数的方法,根据strncpy的函数来扩展strcpy函数的用法
*也省略了strncpy的调用
*/
// char *strcpy(char *dest, const char *src);
// char *strncpy(char *dest, const char *src, size_t n);

char * strcpy(char *dest, const char *src, size_t n )		//通过重载方式扩展strcpy的功能
{
	return strncpy(dest, src, n);							//其函数内部本质是调用了strncpy函数
}
int main()
{
	char *str = "adfhajdhfjkhdfkjfkjfabcde";
	char buf[10] = {0};
	strcpy(buf, str);				//此处会报错,因为赋值的字符串超出了数组的长度
	strcpy(buf, str, 10);			//由于扩展了功能此处不会报错,会输出前10个字符
	printf("%s\n", buf);
}
  1. C编译方式无法编译重载函数
    (1)因为再C++中,编译后的函数符号(函数名)取决于函数名和函数的参数共同决定,因此重载函数之间编译后的函数名也不相同;
    (2)C编译方式不支持重载函数功能,因此编译后会造成函数符号同名,调用函数时就无法确定具体的函数,因此会报错。

2. 基本操作符的重载

2.1 重载运算操作符

  1. 重载不仅可以作用于函数之间,也可以发生在操作符之间,+、 -、 *、 /等;操作符重载也同函数重载一样,只在相同作用域中发生,即在类中重载则只能在类中使用。
  2. 若定义在全局中,将该重载函数设置为类中的友元函数,就可以类中也能使用。若全局与类中定义了相同的操作符重载函数,则默认使用类中的重载。
  3. 语法:将operator 操作符作为函数名,就可以实现对操作符的重载
/*
*本例的目的是实现复数的运算
*由于原有操作符+-等无法实现复数实部和虚部的运算,因此通过重载的方式来扩展这个功能
*复数的实部和虚部通过类的两个成员变量实现
*/

class complex{							//定义复数类
private:
	int a;								//假设为实部
	int b;								//假设为虚部
public:
	complex(int a = 0, int b = 0)
	{
		this->a = a;
		this->b = b;
	}
	complex& operator +(const complex& s)//重载操作符函数的定义
	{
		complex s1;
		s1.a = a + s.a;					//实部与实部相加
		s1.b = b + s.b;					//虚部+虚部
		return s1;
	}
	int getA()							//功能函数
	{
		return a;
	}
	int getB()
	{
		return b;
	}
	~complex(){};						//析构函数
	friend complex& operator -(const complex& s1, const complex& s2);	//将全局操作符重载函数设为友元函数
};

complex& operator -(const complex& s1, const complex& s2)				//在全局作用域中定义操作符重载函数
{
	complex s3;
	s3.a = s1.a - s2.a;
	s3.b = s1.b - s2.b;
	return s3;
}

int main()
{
	complex s1(10, 20);
	complex s2(3, 6);
	complex s3 = s1 + s2;								//使用类中操作符重载函数来进行复数运算
	printf("a = %d\tb = %d\n", s3.getA(), s3.getB());
	complex s4 = s1 - s2;								//使用全局操作符重载函数来进行复数运算
	printf("a = %d\tb = %d\n", s4.getA(), s4.getB());
}

2.2 重载赋值操作符

  1. C++标准库中默认提供了不同类型的赋值操作符的重载函数,这意味着相同类型之间都可以进行赋值;
  2. 但库提供的重载是浅层的赋值,像拷贝构造函数一样,若要进行深层赋值就需要通过重载赋值操作符;
  3. 赋值操作符与拷贝构造函数具有相同的意义,区别在于赋值操作符用于已经定义好的两个对象之间的赋值,而拷贝构造函数用于一个对象对另一个对象构造时的初始化。
class cls{					//定义类
	int* m_p;				//成员变量
public:
	cls(){					//构造函数
		m_p = new int; 
	}
	cls(int i){
		m_p = new int(i);
	}
/*	若无拷贝构造函数和赋值操作符重载函数,这个程序会报内存错误
	//因为此时编译器会调用系统默认的拷贝构造函数,
	//析构函数释放空间时会释放两次同一块内存
	cls(const cls &s)
	{
		m_p = new int(*(s.m_p));
	}
	cls& operator = (const cls &s)
	{
		if (this != &s)
		{
			delete m_p;
			m_p = new int(*(s.m_p));
		}
		return *this;
	}
*/
	int* getP()
	{
		return m_p;
	}
	~cls(){
		delete m_p;
		cout<<"这是析构函数" << endl;
	};
};

int main()
{
	cls s1 = 1;
	cls s2;
	s2 = s1;				//若无赋值操作符重载函数,此处会报错
	cls s3(s1);				//若无自定义拷贝构造函数,此处会报错	
}

2.3 重载数组操作符

  1. string类对象也可以通过数组下标的方式来访问其中的字符,因为C++标准库中数组操作符[]通过重载,使其具有了该功能。

int main()
{
	string str = "a1b2c3d4";
	int cnt = 0;
	for (int i = 0; i < str.length(); i ++)
	{
		if (isdigit (str[i]))				//通过下标访问str中的字符串
		{
			cnt++;							//如果是数字字符,cnt++
		}
	}
	cout << cnt << endl;					//输出4
}
  1. 数组下标访问实际是指针访问a[i] = *(a + i) = *(i + a) = i[a]
  2. 重载数组访问操作符
    (1)因为要访问数组类中的成员变量,因此只能通过类的成员函数重载,不能通过全局函数;
    (2)重载只能有且仅有一个参数;
    (3)可以通过重载传入不同类型的参数;
class arrayReload{
	int a[5];
public:
	arrayReload()
	{
		for(int i = 0; i < 5; i ++)
		{
			a[i] = i;
		}
	}
	int& operator [](int i)			//数组访问操作符重载函数
	{
		return a[i];				//引用是为了可以赋值给a[i];
	}
	int& operator [](string str)	//重载后可以通过字符串访问数组中的元素
	{
		if (str == "1st")
		{
			return a[0];
		}
		if (str == "2nd" )
		{
			return a[1];
		}
	}
};
int main()
{
	arrayReload s1;

	cout << s1[0] << endl;			//通过下标访问
	s1[0] = 10;						//通过数组访问操作符给数组赋值
	cout << s1["1st"] << endl;		//通过字符串访问数组元素
	
}

2.4 重载函数操作符

  1. 函数对象就是通过定义一个类,通过定义该类的对象,用来取代函数的作用;
  2. 函数的对象本质上就是重载函数调用操作符()
/*
*目的:每调用一次函数,就可以获得一个斐波那契数组的元素,并且该函数可以重复调用
*/

class cls{								//通过函数对象方法来实现要求
	int a0;
	int a1;
public:
	cls(){
		a0 = 0;					//默认初始值为0
		a1 = 1;
	}
	cls(int n){					//指定数列中第n项作为初始值
		a0 = 0;
		a1 = 1;
		for (int i = 1; i < n; i ++)
		{
			int ret = a1;
			a1 = a0 + a1;
			a0 = ret;
		}
	}
	int operator()()			//重载函数调用操作符
	{	
		int ret;
		ret = a1;
		a1 = a0 + a1;
		a0 = ret;
		return ret;
	}
	~cls(){};
};
int test()						//通过函数方法来实现要求
{
	int ret;
	static int a0 = 0;			//定义静态局部变量
	static int a1 = 1;
	ret = a1;
	a1 = a0 + a1;
	a0 = ret;
	return ret;
}
int main()
{
	for (int i = 0; i < 10; i ++)
	{
		cout << test() << endl;
	}
	cls s1;
	for (int i = 0; i < 10; i ++)
	{
		cout << s1.operator()() << endl;
	}
}
  1. 上例中test函数可以基本实现功能,但一旦开始就无法从头开始调用,也无法指定某个数字作为数组初始项。因此可以通过函数对象来实现函数无法实现的功能

3. 特殊操作符的重载

3.1 智能指针

3.1.1 普通指针的缺点

  1. 无法控制申请的内存的生命周期,需要手动才能释放;
  2. 若多个对象指向一个内存空间,则结束时会出现重复释放造成内存错误;
  3. 当对指针进行运算时,可能会出现野指针的情况;

3.1.2 重载指针操作符

  1. 为了解决上面的问题,C++可以通过定义类的方式来实现智能指针
  2. 智能指针本质通过定义指针类对象,来代替原来的指针;
  3. 在定义的指针类中,通过成员函数和指针操作符的重载,对普通指针的缺点进行改进;
  4. 指针操作符重载只能在类中进行,且不能包含参数,目前定义一个指针类只能面向一种类型的指针;
  5. 智能指针只能指向堆空间的地址,不能是栈空间,因为智能指针在使用结束后会自动释放,而栈空间在函数结束后也会自动释放,因此若指向栈空间,就会被释放两次,造成内存错误。
class cls{			//定义一个类
	int a;
public:
	cls(){			//构造函数
		a = 0;	
	}
	cls(int i){
		a = i;	
	}			
	int getA()		//功能函数:输出成员变量
	{
		return a;
	}
};
class pointer{		//定义一个指针类
	cls *ps;		//成员变量为cls类的指针
public:
	pointer(){		//构造函数
		ps = NULL;	
	}
	pointer(const cls* p){
		ps = const_cast<cls*>(p);
	}
	pointer(const pointer &p)		//拷贝构造函数
	{
		ps = p.ps;					//当将指向的地址复制给另一个时
		const_cast<pointer&>(p).ps = NULL;		//取消其中一个的指向,避免多个指针指向同一个内存空间
	}
	cls& operator *()			//重载指针操作符
	{
		return *ps;
	}
	cls* operator ->()			//重载指针操作符
	{
		return ps;
	}
	cls* getPs()				//功能函数:输出成员变量
	{
		return ps;
	}
	~pointer(){					//析构函数,释放指向的空间
		cout << "delete" << endl;
		delete ps;	
	}
};

int main()
{
	pointer p1 = new cls(10);		//将new的地址给定义的pointer类对象p1
	cout << p1->getA() << endl;
	cout << p1.getPs() << endl;
	pointer p2 = p1;				//用p1来初始化p2
	cout << p1.getPs() << endl;		//此时为空,避免了指向同一块内存
	cout << p2.getPs() << endl;		//为p1原来指向的空间
//	p2++;							//报错,避免了野指针
}				

3.2 重载逻辑操作符

3.2.1 逻辑操作符概述

  1. 逻辑操作符用来进行逻辑判断,其参数只含有两种语义truefalse(C中无bool类型,用0和非0表示),其结果也是两种语义中的一种;
  2. 逻辑操作符具有短路属性,即当判断第一个参数就可知道结果后,就不再判断第二个参数。
int func(int i)
{
	cout << i << endl;
	return i;
}
int main()
{
	int a = 0;
	int b = 1;
	if(func(0) && func(1))			//由于func(0) == 0;因此不会判断func(1),输出func(0)的值后直接结束判断
	{
		cout << "ture" << endl;	
	}
	else
	{
		cout << "false" << endl;	//输出false
	}
	if(func(0) || func(1))			//由于func(0) == 0;因此判断完后会继续判断func(1),因此输出为 0, 1;
	{
		cout << "ture" << endl;		//输出为true
	}
	else
	{
		cout << "false" << endl;
	}
}

3.2.2 逻辑操作符的重载

  1. 通过重载逻辑操作符,可以实现对象之间的逻辑判断
  2. 但重载的逻辑操作符会丢失短路属性,无法完全实现原生语义
class cls{					//定义类
	int a;
public:
	cls(){					//构造函数
		a = 0;
	}
	cls(int i){
		a = i;
	}
	int getA() const		//获取成员变量函数
	{
		return a;
	}
};

cls func(cls s1)			//区别显示函数
{
	cout << s1.getA() << endl;
	return s1;
}
bool operator&& (const cls&s1, const cls& s2)	//逻辑操作符重载函数
{
	return s1.getA() && s2.getA();
}
bool operator|| (const cls&s1, const cls& s2)
{
	return s1.getA() || s2.getA();
}

int main()
{
	cls s1(0);						//定义cls类对象
	cls s2(1);
	if (func(s1) && func(s2))		//进行对象之间的逻辑判断,输出1, 0
	{
		cout << "true" << endl;
	}
	else
	{
		cout << "false" << endl;	//结果是flase
	}
	if (func(s2) || func(s1))		//进行对象之间逻辑判断,输出 0, 1
	{
		cout << "true" << endl;		//结果是true
	}
	else
	{
		cout << "false" << endl;
	}
}
  1. 程序分析:上例中的逻辑判断无短路属性,因为重载后if (func(s1) && func(s2))本质为operator&& (const cls&s1, const cls& s2),此从在函数是在对参数的进行调用后进行逻辑,因此必须先明确参数的值,而参数的调用先后顺序无法确定,因此不具有短路属性。

注意:在实际工程中应尽量避免重载逻辑操作符
(1)可以通过重载比较操作符来进行判断,即将参数与true进行判断;
(2)也可以通过成员函数来代替逻辑操作符重载函数;

3.3 重载逗号操作符

3.3.1 逗号操作符概述

  1. 逗号操作符可以将多个表达式连接成一个表达式,计算值的顺序是从左到右;
  2. 前n-1个表达式可以没有返回值,连接起来的n个表达式最终值为最后一个表达式的值。
void func(int i)
{
	cout << "i =  " << i << endl;
}

int main()
{	
	int a[3][3] = {						//定义多维数组
		(1, 2, 3),
		(4, 5, 6),
		(7, 8, 9),	
	};
	int i = 0;
	int j = 0;

	while(i < 5)
		func(i),						//输出01234
			i++;						//因为此处是逗号,所以会从左向右的执行,相当于func(i); i++;
	for (i = 0; i < 3; i ++)
	{
		for (j = 0; j < 3; j ++)
		{
			cout << a[i][j] << endl;	//输出369 000 000
		}								//因为三位数组的初始化使用(),并通过,分隔
	}									//因此每一行只保留了最后一个值,因此相当于只初始化了三个值
	(i, j) = 6;
	cout << "i = " << i << endl;		//输出为3,因为for循环使i变成了3
	cout << "j = " << j << endl;		//输出为6, 因为逗号从左向右执行,因此最终值为最右值。
	return 0;
}

3.3.2 逗号操作符的重载

  1. 通过操作符重载,可以实现通过逗号操作符连接多个对象的操作;
  2. 逗号操作符重载与逻辑操作符重载一样,无法完全实现原生语义,因为逗号操作符无法保留从左到右计算值的顺序;
  3. 实际上,使用原生的逗号操作符就可以实现对象之间的连接,并且满足从左向右的顺序,因此无需重载逗号操作符。
class cls{
	int a;
public:
	cls(int i)
	{
		a = i;
	}
	int getA()
	{
		return a;
	}
};

cls& operator ,( const cls& s1, const cls& s2)		//重载逗号操作符函数
{
	return const_cast <cls &>(s2);
}
cls func(cls i)
{
	cout << "i = " << i.getA() << endl;
	return i;
}

int main()
{
	cls s1(10);
	cls s2(20);
	cls ss = (func(s1), func(s2));		//输出为20, 10;但按照从左到右因为10, 20
	cout << ss.getA() << endl;			//输出为20
	return 0;
}

3.4 重载前置和后置操作符

3.4.1 基本概述

  1. 在理论上,前置操作符++i是使用i+1后的值,而i++是先使用i的值后,再将i+1;
  2. 但在实际工程中,原型的前置与后置在编译后无区别,是因为编译器进行了优化;
  3. 优化使得效率更高,但也同时失去了C/C++的原生语义,不可能通过反汇编得到源程序。

3.4.2 重载前置和后置操作符

  1. 前置操作符的本质是将i+1后再使用,使用的是i+1的值;后置本质是将i保存再一个局部变量中,使用局部变量的值,再将i+1;
  2. 重载前置操作符可以通过operator++ (),重载后置需要加占位参数operator ++(int)
  3. 由于是自增或自减,因此前置返回值必须是本身,而后置由于生成一个临时变量,因此返回值是同类型的临时变量;
  4. 虽然在原型中,前置和后置在编译时无区别,但重载后进行对象运算时前置和后置是有区别的,因为后置需要调用栈新生成一个临时对象,因此效率比前置低,在实际开发中,对于对象应尽量使用前置操作符。
class cls{
	int a;
public:
	cls(int i)
	{
		a = i;
	}
	int getA()
	{
		return a;
	}
	cls & operator ++()				//重载前置操作符
	{
		++a;
		return *this;				//注意此处返回值为对象本身,因此用引用
	}
	cls operator ++(int)			重载后置操作符
	{
		cls ret(a);
		a++;
		return ret;					//此处返回值是一个局部对象,因此不能用引用,否则当释放局部对象内存时,引用就会变成野指针。
	}
};
int main()
{
	cls s1(0);
	cout << s1.getA() << endl;		//输出0
	cls s2 = s1++;
	cout << s2.getA() << endl;		//输出0
	cout << s1.getA() << endl;		//输出1
	s1 = 0;
	cls s3 = ++s1;
	cout << s3.getA() << endl;		//输出1
	cout << s1.getA() << endl;		//输出1
}

3.5 类的类型转换

3.5.1 基本类型的转换

  1. 类型之间的转换并不改变数据在内存中二进制的存储方式,改变的只是编译器对于数据的解析方式;
  2. 基本类型之间会进行隐式类型转换,默认原则为小转大在这里插入图片描述
  3. 当两个类型不同的值进行运算时,会默认将小类型转为大类型再进行运算;
int main()
{
	short s = 'a';
	unsigned int ui = 1000;
	int i = -2000;
	double d = i;
	
	cout << "d = " << d << endl;		//输出为-2000;因为int->double是小转大;
	cout << "ui = " << ui << endl;		//输出为1000;
	cout << "ui + i = " << ui + i << endl;		//输出乱码,因为i会默认转换为ui类型,转换后通过unsigned int 的解析方式编程了乱码;
	cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl;		//输出为4;按照小转大原则应输出为2,但编译器为了执行效率,直接转为4个字节。
	return 0;
}

3.5.2 普通类型转换到类类型

  1. 编译器支持普通类型隐式转换成类类型,前提是类中有转换构造函数,且该转换构造函数的参数类型与要转的普通类型相同
  2. 转换构造函数就是有一个参数的构造函数,转换时编译器会自动将普通类型当做传入的参数来构造对象,就相当于将普通类型转为类类型;
class cls{
	int a;
public:
	cls()
	{
		a = 0;
	}
	cls(int i)
	{
		a = i;
	}
	int getA()
	{
		return a;
	}
};
int main()
{
	cls s1 = 10;				//将int类型转换为cls类型
	cout << s1.getA() << endl;
}
  1. 普通类型转换到类类型是编译器的优化处理,但实际中通常禁止将普通类型转为类类型,因此可以在转换构造函数前加explicit关键字禁止编译器的自动优化;
  2. 加了explicit关键字后,编译器就不会自动优化,但若仍需要将转换,可通过强制类型转换的方式;
class cls{
	int a;
public:
	cls(){
		a = 0;
	}
	explicit cls(int i)				//添加explicit关键字,禁止编译器隐式转换普通类型与类类型
	{
		a = i;
	}
	int getA()
	{
		return a;
	}
	cls operator +(const cls& s)
	{
		cls ret;
		ret.a = this->a + s.a;
		return ret;
	}
};

int main()
{
	cls s1;
	s1 = cls(10);				//强制类型转换,将int->cls,实际上是手动调用构造函数生成一个临时对象
	cout << s1.getA() << endl;
	cls s2;
	s2 = s1 + static_cast<cls>(15);	//强制类型转换,对象之间的运算
	cout << s2.getA() << endl;
}

3.5.3 类类型转换到其他类型

  1. 若要将类类型转换到普通类型或其他类类型,可以在类中定义类型转换函数来实现,当类型不一致时会自动调用类型转换函数;operator type(){type ret; return ret;}
  2. 当源类中定义了类型转换函数,且转换的目标类的转换构造函数未加explicit关键字,则会报错。因为编译器无法判断是否使用哪一个函数进行转换,因此两个函数同时作用时会发生冲突;
class cls;					   //声明cls类

class cls1{						//定义一个类cls1
	int a;
public:
	cls1()
	{
		a = 0;
	}
	explicit cls1(int i)		//转换构造函数
	{
		a = i;
	}
	 cls1(const cls& s)			//转换构造函数,可以接收cls类的对象;若不加explicit关键字,会与cls类中的类型转换函数发生冲突
	{
		a = 0;
	}
	int getA()
	{
		return a;
	}
};
class cls{					//定义第二个类cls
	int a;
public:
	cls(){
		a = 0;
	}
	explicit cls(int i)				
	{
		a = i;
	}
	int getA()
	{
		return a;
	}
	operator int()			//类型转换函数,将cls类型转换为int类型
	{
		return a;
	}
	operator cls1()			//类型转换函数,将cls类型转换为cls1类型
	{
		cls1 ret(10);
		return ret;
	}
	
};

int main()
{
	int a;
	cls s1;
	a = s1;						//将cls类型对象赋值给int类型,实际上是s2 = s1.operator int()
	cout << s1.getA() << endl;
	cout << a << endl;
	cls1 s2;
	s2 = s1;					//将cls类型对象赋值给s2类型,实际上是s2 = s1.operator cls1()
	cout << s2.getA() << endl;
}
  1. 转换构造函数可以通过explicit来禁止隐式转换,但无法禁止自动调用类型转换函数,而在C++中应尽量减少编译器进行隐式转换的操作,因此通常采用定义并调用成员函数的方式进行显示类型转换;
//将上例中的operator cls1();函数修改为
cls1 toCls1()
{
	cls1 s1;
	return s1
}
//使用成员函数调用的方式进行类型转换
cls s1;
cls1 s2;
s2 = s1.toCls1();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值