3-16 类型转换构造函数、explicit、运算符,类成员指针

类型转换构造函数

我们通过 类型转换构造函数 和 类型转换运算符 来做到 类型转换。

构造函数:移动构造函数,拷贝构造函数,默认构造函数、普通构造函数

特点:

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;
  }

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值