C++语法学习笔记二十三:类型转换构造函数-运算符-类成员指针

实例代码:


#include <iostream>
#include <string>
#include <vector>

using namespace std;

class TestInt {  //保存0-100之间的一个数字
	//定义一个函数指针类型,代表的函数带一个int 形参,没有返回类型的
	//typedef void(*tfpoint)(int);
	using tfpoint = void(*)(int);

public:
	static void mysfunc(int v1){  //静态成员函数
		int test;
		test = 1;
	}

	//新的类型转换运算符,能本类类型 转换成一个 函数指针类型
	operator tfpoint(){  // const 不是必须加的,所以这里不加
		//必须要返回一个函数指针
		return mysfunc; //函数地址(函数名) 作为函数指针类型返回即可。
	}

public:
	//explicit : 禁止做隐式类型转换
	TestInt(int x = 0) : m_i(x) //类型转换构造函数(也是一个只带一个参数的普通构造函数),本构造函数就可以,将一个int数字转换成类类型TestInt
	{
		if (m_i < 0) m_i = 0;
		if (m_i > 100) m_i = 100;
	}

	//类型转换运算符,可以把本类类型对象转换成其他类型。
	operator int() const{
		return m_i;
	}

	//operator double()const{
	//
	//}

	int m_i;
};


class CT1{
public:
	CT1(int ct){} // 类型转换构造函数
};

class CT2{
public:
	CT2(int ct){} // 类型转换构造函数
};

void testfunc(const CT1& c){};
void testfunc(const CT2& c){};

class CT{
public:
	void ptfunc(int tmpvalue) { cout << "ptfunc普通成员函数被调用, value=" << tmpvalue << endl; }
	
	//类中有虚函数则编译器会给该类生成虚函数表
	virtual void virtualfunc(int tmpvalue){ cout << "virtualfunc虚成员函数被调用, value=" << tmpvalue << endl; }
	static void staticfunc(int tmpvalue){ cout << "staticfunc静态成员函数被调用, value=" << tmpvalue << endl; }

	int m_a; //普通成员变量
	static int m_stca;// 静态成员变量,属于类, 不属于对象
};

int CT::m_stca = 1; // 静态成员变量的定义

int main() {

	//我们需要通过转换构造函数,和 类型转换运算符 来做到 类型转换

	//一:类型转换构造函数,比如,他们能够把一个数字转换成一个类对象。
	//构造函数种类:常规不带参数的(默认构造函数),带一个参数,带两个参数....
		//拷贝构造函数,移动构造函数。

	//特点回顾:
	//a) 以类名作为函数名
	//b) 没有返回值
	//有一种构造函数,叫“类型转换构造函数”,主要能力是:它可以将某个其他的数据类型转换成该类类型的对象。
	//类型转换构造函数的特点:
	//a) 只有一个参数,该参数又不是本类的const 引用。(const &A),该参数其实就是待转换的数据类型。所以显然待转换的数据类型都不应该是本类类型。
	//b) 在类型转换构造函数中,我们要指定转换的方法(在这个函数中要干什么);

	TestInt ti = 12; //隐式类型转换,将数字12转换成了 TestInt对象(调用了类型转换构造函数)
					//编译器用12这个数字通过调用TestInt类的类型构造函数来创建一个临时的TestInt对象,并把这个对象构造到ti这个预留空间里去了
	//TestInt ti = TestInt(12); //这也是调用类型转换构造函数
	TestInt ti2(22); //调用了类型转换构造函数,但这里并没有进行隐式类型转换。

	//二:类型转换运算符(类型转换函数):能力和类型转换构造函数能力相反。
	//是特殊的成员函数,它能够将一个类类型对象 转成 某个其他数据类型。

	//格式:
	//operator type() const;
	//a) const 是可选项,const 表示一般不应该改变待转换对象内容,但不是必须有const
	//b) type :表示要转换成的某种类型。只要是能够作为函数返回的类型,都可以;数组指针,函数指针,引用等等类型也都可以
	//c) 类型转换运算符,没有形参(形参列表为空),因为类型猪娜辉运算符都是隐式执行的,所以根本也没有办法给它传递参数。
		//同时,也不能指定返回类型,但是,它却能返回一个type指定的类型的值的;
	//d) 必须定义为类的成员函数。

	TestInt ti3 = 12;
	TestInt ti4;
	ti4 = 6; //编译器用6生成临时的TestInt对象(调用TestInt类型转换构造函数),又调用赋值运算符把临时对象的内容给了 ti4


	//int k = ti4 + 5; // 11: 调用operator int() const 将ti4 转换成了 int ,再和5做加法运算,结果给k
					//ti4 转int是隐式类型转换
	int k2 = ti4.operator int() + 5;//显示调用。没有形参,所以()内为空。

	//(2.1) 显示的类型转换运算符 explicit;

	//(2.2) 有趣范例:类对象转换为函数指针
	 // operator tfpoint()
	TestInt myi(12);
	myi(123);//看起来是个可调用对象的感觉。相当于调用了两个函数:
			//(1)类型转换运算符【转换成函数指针类型】
			// (2) 通过函数指针调用具体的函数
	//(myi.operator TestInt::tfpoint())(123);

	//三:类型转换的二义性问题
	//二义性:这么干也行,那么干也行,导致编译器不知道该怎么干,所以编译器只能报错。
	TestInt aa;
	//int abc = aa + 12; //二义性   如果放开的 operator double()const{}
	//建议:在一个类中,尽量只出现一个类型转换运算符;
	//testfunc(123); //二义性,因为123是个int类型,可以转换成CT1对象,也可以转换成CT2类型对象。
	testfunc(CT1(123)); //明确调用的是 void testfunc(cosnt CT1& C) {};

	//四:类成员函数指针 : 是个指针,指向类成员函数
	//(4.1) 对于普通成员函数  的函数指针
	//格式: 类名::*函数指针变量名      来声明普通成员函数指针,
	//       &类名::成员函数名           来获取类成员函数地址,   “这是个真正的内存地址”;
	
	//定义一个普通的类成员函数指针
	void (CT::*myfpointpt)(int); //一个类成员函数指针变量的定义,变量名字为 myfpointpt
	myfpointpt = &CT::ptfunc; // 类成员函数指针变量 myfpointpt被赋值
	//大家注意:成员函数是属于类的,不属于类对象,只要有类在就有成员函数地址在。
	//但是你若要使用这个成员函数指针,就必须要把它绑定到一个类对象上才能调用。
	//使用函数指针的格式 : “类对象名 * 函数指针变量名”来调用,如果是个对象指针,则调用格式 “指针名->*函数指针变量名”来调用

	CT ct, *pct;
	pct = &ct;
	(ct.*myfpointpt)(100); //对象ct ,调用指针变量 myfpointpt所指向的成员函数 : ptfunc;
	(pct->*myfpointpt)(200); //对pct所指的对象,调用指针变量 myfpointpt所指向的成员函数 : ptfunc;

	//(4.2) 对于虚函数
	void (CT::*myfpointvirtual)(int) = &CT::virtualfunc; //“这是个真正的内存地址”;
	//也必须要绑定到类对象上才能调用
	(ct.*myfpointvirtual)(100); //对象 ct ,调用指针变量myfpointvirtual所指向的成员函数 virtualfunc;
	(pct->*myfpointvirtual)(200);//对pct所指的对象,调用指针变量myfpointvirtual所指向的成员函数 virtualfunc;

	//(4.3) 对于静态成员函数
	//使用 “*函数指针变量名” 来声明静态成员函数指针,使用 “&类名::成员函数名”来获取类成员函数地址,这个也是真正的地址
	//定义一个静态的类成员函数指针并赋值
	void(*myfpointstatic)(int) = &CT::staticfunc;
	myfpointstatic(100); //直接使用静态成员函数指针名即可调用

	//五:类成员变量指针
	//(5.1) 对于普通成员变量
	int CT::*mp = &CT::m_a; //定义一个类成员变量指针,大家这里注意这种写法
							//ox00000 ,并不是真正意义上的指针。
							// 它不是指向内存中某个地址,而是该成员变量,与该类对象指针之间的偏移量。

	CT ctesttmp; //当生成类对象时,如果这个类中有虚函数表,则对象中,就会有一个指向这个虚函数表的指针,这个指针占用4个字节。

	ctesttmp.*mp = 189;//通过类成员变量指针来修改成员变量值,等价于ct.m_a = 189;

	//(5.2) 对于静态成员变量
	//这种指向静态成员变量的指针,是有真正的内存地址的;
	int *stcp = &CT::m_stca; //定义一个静态成员变量指针
	*stcp = 798; //等价于 CT::m_stca = 798;
	cout << *stcp << endl; // 796;


	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值