类型转换构造函数
我们通过 类型转换构造函数 和 类型转换运算符 来做到 类型转换。
构造函数:移动构造函数,拷贝构造函数,默认构造函数、普通构造函数
特点:
1、以类名作为函数名
2、没有返回值;
类型转换构造函数特点
有一种构造函数叫“类型转换构造函数”,主要能力是:它可以将某个其他的数据转换成该类类型的对象。特点:
1、只有一个参数,该参数又不是本类的const引用。(const &A),该参数其实就是带转换的数据类型。所以显然带转换的数据类型都不应该是本类类型。
2、在类型转换构造函数中我们要制定转换的方法(在这个函数中要干什么);
显示类型转换运算符:explicit
class TypeInt{
public:
int m_int;
public:
//explicit TypeInt(const int &i = 0):m_int(x) explicit可以禁止做隐式类型转换
TypeInt(const int &i = 0):m_int(x)
{
if (m_int < 0) m_int = 0;
if (m_int > 100) m_int = 100;
}
};
int main(){
TypeInt ti = 12; //隐式类型转换,将数字12转换成了TypeInt对象
//编译器用12这个数字通过调用typeInt类的类型构造函数来创建一个
//临时对象,并把这个对象构造到了ti的预留空间
TypeInt ti2(22); //这里调用了类型转换构造函数,但是没有进行隐式类型转换
TypeInt ti3;
ti3 = 6; //这里先将6调用类转换构造函数将6转换成TypeInt类型对象,然后调用赋值运算
//符将这个对象给ti3,这里我们没有定义拷贝赋值运算符,所以系统自动生成了
//一个默认的拷贝赋值运算符
}
类型转换构造函数也是一个带有一个参数的普通构造函数。
类型转换运算符(类型转换函数)
能力和类型转换构造函数相反。他能够将一个类类型对象 转成 某个其他数据类型,格式:
operator type() const
1、const是可选项,const表示一般不应该改变带转换对象内容,但不是必须有const
2、type:表示要转换成的某种类型。只要能够作为函数返回类型都可以;数组指针,函数指针,引用都可以
3、类型转换运算符没有形参,因为类型转换运算符都是隐式执行的,所以,根本没法给它传递参数。同事 ,也不能指定返回类型,但是它却能返回type指定的值。
4、必须定义为类的成员函数。
class TypeInt{
public:
int m_int;
public:
//explicit TypeInt(const int &i = 0):m_int(x) explicit可以禁止做隐式类型转换
TypeInt(const int &i = 0):m_int(x)
{
if (m_int < 0) m_int = 0;
if (m_int > 100) m_int = 100;
}
//explicit operator int() const //防止编译器做隐式类型转换
operator int() const
{
return m_int;
}
};
int main(){
TypeInt ti3;
ti3 = 6;
int k = ti3 + 5; //隐式类型转换。此处会调用类型转换运算符将ti3转换成了int,在与5
//做加法
//加explicit后,此处会报错
int k2 = ti3.operator int() + 5; //显示调用。没有形参,所以()为空
int k3 = static_cast<int>(ti3) + 5; //这种方式也会调用类型转换运算符
}
指针类型转换
class TypeInt{
//typedef void(*tfpoint)(int); 定义函数指针
using tfpoint = void(*)(int);
public:
int m_int;
public:
static void myfunc(int v){
int test;
test = 1;
}
TypeInt(const int &i = 0):m_int(x){}
operator tfpoint() //const 不是必须加
{
return myfunc;
}
};
int main(){
TypeInt myi(12);
myi(123); //看起来是个可调用对象的感觉。相当于调用了两个函数:1、类型转换运算符转换成函数指针类型 2、通过函数指针调用具体的函数
myi.operator TypeInt::tfpoint()(123); //第一个圆括号之前表示类的指针类型转换函
//数,返回了myfunc函数,第二个括号表示表
//示给myfunc函数的参数123
}
类型转换的二义性问题
二义性:这么招可以,那么招也行,所以只能报错。
建议:在一个类中,尽量只出现一个类型转换运算符。
class CT1{
public:
CT1(int x){}
};
class CT2{
public:
CT2(int x){}
};
void testfunc(const CT1 &C) {}
void testfunc(const CT2 &C) {}
int main(){
testfunc(100);//报错,会造成二义性,因为100是int类型可以转换成CT1对象也可以转换成
//CT2对象
testfunc(CT1(100)); //可以,意味着设计缺陷
}
类成员函数指针:是个指针,指向类成员函数
格式:类名::*函数指针变量名 来声明普通成员函数指针
用 &类名::成员函数名 来获取成员函数地址
使用函数指针的格式是:类对象名.*函数指针变量名,如果是个指针对象则调用格式是:指针名->*函数指针变量名,普通的成员函数地址是一个真正的地址
#include <iostream>
using namespace std;
class cT
{
public:
void ptfunc(int tempvalue) {
cout << "ptfunc 普通成员函数被调用value="<<tempvalue <<endl;
}
virtual void virtualFunc(int tempvalue) {
cout <<"virtualfunc 虚成员函数被调用,vallue=" <<tempvalue <<endl;
}
static void staticfunc (int tempvalue) {
cout << "staticfunc 静态成员函数被调用,value=" <<tempvalue <<endl;
}
};
int main()
{
void (cT::*myfpointer) (int) ;//一个类成员函数指针变量的定义,变量名为myfunc
myfpointer = &cT::ptfunc;//类成员函数指针变量myfpointer被赋值
// 注意:成员函数是属于类的,不属于类对象。只要有类在就有成员函数地址在。
// 但是你若使用这个成员函数指针,就必须要把它绑定到一个类对象才能使用。
cT ct ,*pct;
pct = &ct;
(ct.*myfpointer)(100) ;//对象ct
(pct->*myfpointer) (200) ;//对pct所指的对象
return 0;
}
虚成员函数
#include <iostream>
using namespace std;
class cT
{
public:
void ptfunc(int tempvalue) {
cout << "ptfunc 普通成员函数被调用value="<<tempvalue <<endl;
}
virtual void virtualFunc(int tempvalue) {
cout <<"virtualfunc 虚成员函数被调用,vallue=" <<tempvalue <<endl;
}
static void staticfunc (int tempvalue) {
cout << "staticfunc 静态成员函数被调用,value=" <<tempvalue <<endl;
}
int m_a; //普通成员函数
static int m_staca; //静态成员变量,属于类,不属于对象
};
int cT::m_staca = 1; //静态成员变量的定义。
int main()
{
void (cT::*myfpointervirtual) (int) = &cT::virtualFunc;
//这是个真正的地址。
//也必须绑定到类对象上才能调用
(ct.*myfpointervirtual)(100) ;//对象ct
(pct->*myfpointervirtual) (200) ;//对pct所指的对象
}
静态成员函数
这个也是真正的地址定义一个静态的类成员函数指针并赋值
使用 : *函数指针变量名 来声明静态成员函数指针,
使用 : &类名::成员函数名 来获取成员函数的地址 也是真正的地址
#include <iostream>
using namespace std;
class cT
{
public:
void ptfunc(int tempvalue) {
cout << "ptfunc 普通成员函数被调用value="<<tempvalue <<endl;
}
virtual void virtualFunc(int tempvalue) {
cout <<"virtualfunc 虚成员函数被调用,vallue=" <<tempvalue <<endl;
}
static void staticfunc (int tempvalue) {
cout << "staticfunc 静态成员函数被调用,value=" <<tempvalue <<endl;
}
int m_a; //普通成员函数
static int m_staca; //静态成员变量,属于类,不属于对象
};
int cT::m_staca = 1; //静态成员变量的定义。
int main()
{
void (*myfpointerstatic) (int) = &cT::staticfunc;
myfpointerstatic(120) ; //直接使用静态成员函数指针名即可调用
return 0;
}
普通类成员变量指针
#include <iostream>
using namespace std;
class cT
{
public:
void ptfunc(int tempvalue) {
cout << "ptfunc 普通成员函数被调用value="<<tempvalue <<endl;
}
virtual void virtualFunc(int tempvalue) {
cout <<"virtualfunc 虚成员函数被调用,vallue=" <<tempvalue <<endl;
}
static void staticfunc (int tempvalue) {
cout << "staticfunc 静态成员函数被调用,value=" <<tempvalue <<endl;
}
int m_a; //普通成员函数
static int m_staca; //静态成员变量,属于类,不属于对象
};
int cT::m_staca = 1; //静态成员变量的定义。
int main()
{
int cT::*mp = &cT:: m_a; //定义一个类成员变量指针
//不是真正的地址
//而是该成员变量,与该类对象指针之间的偏移量
cT ctestmp; //类中有虚函数就会生成虚函数表,类中有虚函数表,对象就会有一个指针,指向虚函数表,四个字节
ctestmp.*mp = 189; //通过类成员变量指针来修改成员变量值,等价于 ct.m_a = 189;
return 0;
}
对静态成员变量
这种指向静态成员变量的指针,是有真正的内存地址
#include <iostream>
using namespace std;
class cT
{
public:
void ptfunc(int tempvalue) {
cout << "ptfunc 普通成员函数被调用value="<<tempvalue <<endl;
}
virtual void virtualFunc(int tempvalue) {
cout <<"virtualfunc 虚成员函数被调用,vallue=" <<tempvalue <<endl;
}
static void staticfunc (int tempvalue) {
cout << "staticfunc 静态成员函数被调用,value=" <<tempvalue <<endl;
}
int m_a; //普通成员函数
static int m_staca; //静态成员变量,属于类,不属于对象
};
int cT::m_staca = 1; //静态成员变量的定义。
int main()
{
int *stcp = &cT::m_staca;
*msta = 798; //等价于 cT::m_sta = 122
return 0;
}