C++類 --- 類型轉換構造函數、運算符,類成員指針

今天呢,和大家聊一聊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>

u[sin](http://c.biancheng.net/ref/sin.html)g 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 = c1; //相當於 double f = Complex::operator double(&c1);
 cout<<"f = "<<f<<endl;
 f = 12.5 + c1 + 6; //相當於 f = 12.5 + Complex::operator double(&c1) + 6;
 cout<<"f = "<<f<<endl;
 int n = Complex(43.2, 9.3); //先轉換爲 double,再轉換爲 int
 cout<<"n = "<<n<<endl;
 return 0;
}

運行結果:
f = 24.6
f = 43.1
n = 43

類型轉換函數和運算符的重載非常相似,都使用 operator 關鍵字,因此也把類型轉換函數稱爲類型轉換運算符

關於類型轉換函數的說明

  1. type 可以是內置類型、類類型以及由 typedef 定義的類型別名,任何可作爲函數返回類型的類型(void 除外)都能夠被支持。一般而言,不允許轉換爲數組或函數類型,轉換爲指針類型或引用類型是可以的。
  2. 類型轉換函數一般不會更改被轉換的對象,所以通常被定義爲 const 成員。
  3. 類型轉換函數可以被繼承,可以是虛函數。
  4. 一個類雖然可以有多個類型轉換函數(類似於函數重載),但是如果多個類型轉換函數要轉換的目標類型本身又可以相互轉換(類型相近),那麼有時候就會產生二義性。以 Complex 類爲例,假設它有兩個類型轉換函數:
operator double() const { return m_real; } //轉換爲double類型
operator int() const { return (int)m_real; } //轉換爲int類型

那麼下面的寫法就會引發二義性:

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++類就講到這裏啦,希望大家能給我點個贊哦!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章