美文网首页IT@程序员猿媛互联网@时事传播C/C++程序设计专题
C++系列 --- 类型转换构造函数、运算符,类成员指针

C++系列 --- 类型转换构造函数、运算符,类成员指针

作者: 307656af5a04 | 来源:发表于2019-04-25 05:58 被阅读68次

    今天呢,和大家聊一聊C++中的类型转换构造函数、类型转换运算符(函数)以及类成员指针。

    简单的来讲,类型转换构造函数的作用就是将一个变量通过构造函数转换为类类型;类型转换运算符就是将类类型转换为已有的变量类型;类成员指针在C++中用于对类中的成员进行操作。

    一、类型转换构造函数、运算符

    C++中没有返回类型的函数有3个,构造函数、析构函数、类型转换函数。

    1、转换构造函数

    在C++中,类的构造函数可以省略不写,这时C++会为它自动创建一个隐式默认构造函数(implicit default constructor);也可以由用户定义带参数的构造函数,构造函数也是一个成员函数,他可以被重载;当一个构造函数只有一个参数,而且该参数又不是本类的const引用时,这种构造函数称为转换构造函数。

    一个构造函数接收一个不同于其类类型的形参,可以视为将其形参转换成类的一个对象;像这样的构造函数称为转换构造函数。

    转换构造函数:预定义类型转换成类类型。

    凡是需要将系统预定义的数据类型转换为类类型的都要用到转换构造函数。

    除了创建类对象之外,转换构造函数还为编译器提供了执行隐式类型转换的方法。只要在需要类的类型值的地方,给定构造函数的形参类型的值,就将由编译器执行这种类型的转换。

    class IntClass
    
    {
    private:
       int value;
    public:
     //转换int的转换构造函数
       IntClass(int intValue)
       {
       value = intValue;
       }
       int getValue() const 
       { return value; }
    };
    

    由于构造函数 IntClass(int) 只接收一个类型不同于 IntClass 的单个形参,所以它是一个转换构造函数。

    只要上下文需要类对象,但提供的却是构造函数形参类型的值,则编译器将自动调用转换构造函数,这会在以下 4 种不同的上下文环境中出现:

    1)该类的一个对象使用转换构造函数的形参类型的值进行初始化。例如:

    IntClass intObject = 23;
    

    2)该类的一个对象被赋给了一个转换构造函数形参类型的值。例如:

    intObject = 24;
    

    3)函数需要的是该类的类型的值形参,但传递的却是构造函数的形参类型的值。例如,假设定义了下面这样一个函数:

    void printValue(IntClass x)
    {
     cout << x.getValue();
    }
    

    但是在调用它的时候却传递了一个整数给它:

    printValue(25);
    

    编译器将使用转换构造函数将整数 25 转换为 IntClass 类的对象,然后将该对象传递给该函数。如果形参是一个指针或对 IntClass 对象的引用,则编译器将不会调用转换构造函数。只有在形参按值传递时,才会调用转换构造函数。

    4)声明类的类型的返回值的函数实际上返回的却是转换构造函数的形参类型的值。例如,编译器将接收以下函数:

    IntClass f(int intValue)
    {
      return intValue;
    }
    

    请注意,虽然已经将 IntClass 声明为其返回类型,但是该函数仍然会返回整数类型的值,于是编译器也将再次隐式地调用转换构造函数,将整数 intValue 转换为一个 IntClass 对象,这个对象正是需要从函数返回的对象。

    实例:

    //Convert.h的内容
    #include <iostream>
    using namespace std;
    
    class IntClsss
    {
    private:
       int value;
    public:
       //Convert constructor from int
       IntClass(int intValue)
       {
       value = intValue;
       }
       int getValue() const { return value; }
    };
    
    //Convert.cpp 的内容
    #include "Convert.h"
    IntClass f(int intValue)
    {
     return intValue;
    }
    void printValue(IntClass x)
    {
     cout << x.getValue();
    }
    
    //mian函数
    //This program demonstrates 
    //the action of convert constructors.
    #include "Convert.h"
    // Function prototypes.
    void printValue (IntClass);
    IntClass f(int);
    
    int main()
    {
     // Initialize with an int
     IntClass intObject = 23;
     cout << "The value is " 
          << intObject.getValue() << endl;
    
     // Assign an int
     intObject = 24;
     cout << "The value is " 
          << intObject.getValue() << endl;
    
     //Pass an int to a function 
     //expecting IntClass
     cout << "The value is ";
     printValue(25);
     cout << endl;
    
     // Demonstrate conversion on a return
     intObject = f(26);
     cout << "The value is ";
     printValue(intObject);
     return 0;
    }
    

    程序输出结果:
    The value is 23
    The value is 24
    The value is 25
    The value is 26

    2、类型转换函数(运算符)

    用转换构造函数可以将一个类型数据转换成类的对象,但不能将一个类的对象转换成一个类型数据;因此我们需要另一种方法来实现这种功能:
    C++提供了类型转换函数来解决这种问题:
    类型转换函数:类类型转换成其他类型(系统预定义类型)

    类型转换函数的语法格式为:

    operator type()
    {
       return data;
    }
    

    operator 是 C++ 关键字,type 是要转换的目标类型,data 是要返回的 type 类型的数据。

    因为要转换的目标类型是 type,所以返回值 data 也必须是 type 类型。既然已经知道了要返回 type 类型的数据,所以没有必要再像普通函数一样明确地给出返回值类型。这样做导致的结果是:类型转换函数看起来没有返回值类型,其实是隐式地指明了返回值类型。

    类型转换函数没有返回类型,但是要return 目标类型的数据,没有参数,只能定义为类的成员函数。

    总结:
    对于转换构造函数和类型转换函数,重点还是分清楚什么时候需要将类类型转换为预定义类型,什么时候将预定义类型转换为类类型,分清楚后再去定义相关函数。同时上述两种转换都可以用以下格式: 类型名(类类型或预定义类型)

    实例:为 Complex 类添加类型转换函数,使得 Complex 类型能够转换为 double 类型

    #include <iostream>
    using namespace std;
    
    //复数类
    class Complex
    {
    public:
       Complex(): m_real(0.0), m_imag(0.0){ }
       Complex(double real, double imag): 
              m_real(real), m_imag(imag){ }
    
    public:
       friend ostream & operator<<(ostream &out, 
                 Complex &c);
    
       friend Complex operator+(const Complex &c1, 
                 const Complex &c2);
    
        //类型转换函数
       operator double() const { return m_real; } 
    private:
       double m_real; //实部
       double m_imag; //虚部
    };
    
    //重载>>运算符
    ostream & operator<<(ostream &out,
     Complex &c)
    {
     out << c.m_real <<" + "
         << c.m_imag <<"i";;
     return out;
    }
    
    //重载+运算符
    Complex operator+(const Complex &c1,
     const Complex &c2)
    {
     Complex c;
     c.m_real = c1.m_real + c2.m_real;
     c.m_imag = c1.m_imag + c2.m_imag;
     return c;
    }
    
    int main()
    {
     Complex c1(24.6, 100);
    // 相当于 double f = 
    // Complex::operator double(&c1);
     double f = c1; 
     cout<<"f = "<<f<<endl;
     // 相当于 f = 12.5 + 
     // Complex::operator double(&c1) + 6;
     f = 12.5 + c1 + 6;
     cout<<"f = "<<f<<endl;
     //先转换为 double,再转换为 int
     int n = Complex(43.2, 9.3);
     cout<<"n = "<<n<<endl;
     return 0;
    }
    

    运行结果:
    f = 24.6
    f = 43.1
    n = 43

    类型转换函数和运算符的重载非常相似,都使用 operator 关键字,因此也把类型转换函数称为类型转换运算符

    关于类型转换函数的说明

    1. type 可以是内置类型、类类型以及由 typedef 定义的类型别名,任何可作为函数返回类型的类型(void 除外)都能够被支持。一般而言,不允许转换为数组或函数类型,转换为指针类型或引用类型是可以的。

    2. 类型转换函数一般不会更改被转换的对象,所以通常被定义为 const 成员。

    3. 类型转换函数可以被继承,可以是虚函数。

    4. 一个类虽然可以有多个类型转换函数(类似于函数重载),但是如果多个类型转换函数要转换的目标类型本身又可以相互转换(类型相近),那么有时候就会产生二义性。以 Complex 类为例,假设它有两个类型转换函数:

    //转换为double类型
    operator double() const { return m_real; } 
    //转换为int类型
    operator int() const { return (int)m_real; } 
    

    那么下面的写法就会引发二义性:

    Complex c1(24.6, 100);
    loat f = 12.5 + c1;
    

    二、类成员指针

    1、指向类的数据成员的指针:
    声明格式如下:
    <类型说明符> <类名>::* <指针变量名>;

    2、指向类的成员函数的指针:
    声明格式如下:
    <类型说明符> (<类名>::*<指针名>)(<参数表>);

    class A
    {
    private:
       int a;
    public:
       int c;
    
    public:
       A(int i)
       {
         a = i;
       };
    
       int Fun(int b)
       {
         return ((a * c) + b);
       };
    };
    

    定义一个指向类A的数据成员c的指针,其格式如下:

    int A::* pc = &(A::c);
    

    定义一个指向类A的成员函数Fun()的指针,其格式如下:

    int (A::*pFun)(int) = A::fun;
    

    int A::*pFun(int);
    pFun = A::fun;
    

    由于类不是运行时存在的对象,所以在使用这类指针的时候,要定义类的一个对象,然后通过这个对象来访问这类指针所指向的成员;

    A a;
    a.*pc = 8; //为对象a的数据成员c赋值8;
    A* pa;
    pa = &a;
    pa->*pc = 9; //通过指向对象的指针来为指向对象成员的指针所指向的数据成员赋值;
    

    其中,运算符 "." 和 "->" 都是通过指向类成员的指针来操作对象成员的运算符;

    3.指向普通函数的指针的定义格式:

    <类型说明符> (*<指向函数的指针名>)(<参数表>);

    赋值:
    <指向函数的指针名> = <函数名>;

    调用:
    (*<指向函数的指针名>)(<实参表>);

    class B
    {
    private:
       int a;
    public:
       int c;
     public:
       A(int i) { a = i;};
       int Fun(int b) { return ((a * c) + b); };
    };
    
    int main(int argc, char** argv)
    {
       B x(8)
       int B::* pc = NULL; //声明指向类数据成员的指针pc;
       pc = &(A::c); //为指向类数据成员的指针pc赋值;
       x.*pc = 9; //通过指向类数据成员的指针pc为对象的成员赋值;
       int (B::*pFun)(int); //声明指向类成员函数的指针pFun;
       pFun = A::Fun; //为指向类成员函数的指针pFun赋值为A::Fun;
       A* px = &x; //声明指向类的对象x的指针px;
       cout << (px->*pFun)(5); //通过指向对象x的指针px来访问指向对象x的成员函数的指针pFun,并调用指向对象的成员函数指针所指向的成员函数;
       return 0;
    }
    

    好了,今天的C++到这里就结束了,喜欢的朋友给我点个赞哦!!!

    相关文章

      网友评论

        本文标题:C++系列 --- 类型转换构造函数、运算符,类成员指针

        本文链接:https://www.haomeiwen.com/subject/uelmwqtx.html