- 浏览: 42170 次
- 性别:
- 来自: 大连
最新评论
(1)隐式转换发生的时机:当传递给操作符或者函数的参数与指定类型不匹配时,编译器将会“偷偷地”进行转换,此时就是发生了隐式转换。
(2)隐式转换发生的条件:
(a)编译器原来就支持地转换:比如float型向int型转换,子类的对象(指针)向父类的对角(指针)转换,非const对象(指针)向const对象(指针)转换等等。
(b)当有类型转换操作符的时候。如果类型匹配且有必要,编译器会自动调用它。
(c)当类有一个参数个数为1的构造函数的时候。如果类型匹配有必要,编译器会自动调用它。
现在主要说明(b),(c)两点:
类型转换操作符,是一个拥有奇怪名字的member funtion:关键字operator之后加上一个类型名称。如下:
class Rational
{
public:
Rational(int x,int y):m_x(x),m_y(y){}
operator double()const;//将Rational转换为double.
private:
int m_x;
int m_y;
};
Rational::operator double()const //实现
{
return static_cast<double>(m_x)/m_y;
}
如果在main函数中这样调用:
Rational rat(1,2);
cout<<rat<<endl;//打印0.5
同于编译器发现不存在任何operator<<可以接受一个Rational类型,但它会想尽办法让函数调用成功。在本例中,编译器发现只要调用Rational::double操作符便可以将rat转换为double,调用动作便会成功。于是上述代码将rat以double输出。
当类有一个参数个数为1的构造函数的时候,也可能发生隐式类型转换。
考虑以下代码:
Template<class T>
class Array
{
public:
Array(int lowBound,int highBound);
Array(int size);
T& operator[](int index);
......
};
上述class的第一个constructor允许clients指定某个范围内的数组索。身为一个双自变量constructor,此函数没有资格成为类型转换函数。第二个constructor允许用户只指定数组的元素个数,便可以定义出Array
objects。它可以被用来作为一个类型转换函数,结果导致一些意外的结果。
例如:考虑一个用来对Array<int>对象进行比较的函数,以及一小段代码:
bool operator == (const Array<int>& lhs,const Array<int>& rhs);
Array<int> a(10);
Array<int> b(10);
......
//初始化
for(int i = 0;i < 10; ++i)
{
if( a == b[i]) //“a”应该是“a[i]”才对
{
do something ......
}
当试图将a的每一个元素拿来和b的对应元素比较时,当键入a时却意外地遗漏了下标。然而编译器却没有报错,原因是它看到一个operator ==,夹带着类型为Array<int>的自变量a和类型为int的自变量b[i],虽然没有这样的operator == 可以调用,但是编译器却注意到,只要调用Array<int> constructor(需要一个int作为自变量),它就可以将int转为Array<int> object,从而可以调用operator == (const Array<int>&
lhs,const Array<int>& rhs)。于是拿a的内容来和一个大小为b[i]的临时数组做比较,从而可能导致不可预料的结果。
(3)解决办法:
对于因类型转换操作符引起的最好办法就是提供转换的成员函数来代替转换操作符。如标准库中string类转换到char*时提供函数:c_str()。通过显式地调用成员函数而不是“默默地”调用转换操作符。
对于第二种情况说两种办法。第一是使用关键字explicit来修饰构造函数,如:
template<class T>
class Array
{
public:
......
explicit Array(int size);
......
};
这样这个构造函数便只能显式地调用了,上述if( a == b[i])语句便会报错,因为编译器不会把b[i]作为参数而调用Array(int size)这个构造函数,从而会因为“==”两边的类型不匹配而报错。
第二个办法是使用内部类。如下:
template<class T>
class Array
{
public:
class ArraySize
{
public:
ArraySize(int numElements):theSize(numElements){}
int size()const{ return theSize;}
private:
int theSize;
};
Array(int lowBound,int highBound);
Array(ArraySize size);//注意这个新的声明
......
};
在这里,把ArraySize嵌套放进Array内,用来修饰Array构造函数参数。
现在考虑当我们通过Array的“单自变量构造函数”定义一个对象时,会发生什么事情:
Array<int> a(10);
编译器被要求调用Array<int>class 中的一个自变量为int的构造函数,但其实并不存在这样的构造函数。编译器知道它能够将int自变量转换为一个临时的ArraySize对象,而该对象正是Array<int>构造函数需要的,所以编译器便执行了这样的转换。于是“以一个int自变量构造起一个Array对象”这个事实依然有效。再次考虑这段代码:
Array<int> a(10);
Array<int> b(10);
......
for(int i = 0;i < 10;++i)
if( a == b[i]) //"a"应该是“a[i]” 如今这形成了一个错误。
编译器需要一个类型为Array<int>的对象在“==”右手边,得以针对Array<int> 对象调用operator == ,但是此刻并没有“单一自变量,类型为int”这样的构造函数。此外,编译器不能考虑将一个int转换为一个临时性的ArraySize对象,然后再根据这个临时对象产生必要的Array<int>对象,因为那将调用两个用户制定转换行为(这是不允许的),一个将int转换为ArraySize,另一个将ArraySize转换为Array<int>。如此的转换程序是禁止的,所以编译器对以上代码发出错误消息。
(4)隐式转换与临时对象
首先声明一下,这里我们所讲的临时对象,并不是指一个短暂需要的对象(如这里的temp): int temp = a,a = b,b = temp 。C++真正的临时对象是不可见的---不会出现在你的源代码中。只要你产生了一个non-heap object而没有为它命名,便诞生了一个临时对象。此等匿名对象通常发生于两种情况:一是当隐式类型转换被施行起来以求函数调用能够成功;二是当函数返回对象的时候。这里主要讲第一种情况。看以下代码:
size_t countChar(const string& str,char ch);
char buffer[MAX_STRING_LEN];
char c;
//读入一个char和一个string
cin>>c>>setw>>(MAX_STRING_LEN)>>buffer;
cout<<"There are "<<countChar(buffer,c)<<"occurrences of the character"<<c<<" in "<<buffer<<endl;
看countChar的调用动作。其第一自变量是个char数组,但是相应的函数参数类型却是const string&。之所以会调用成功,是因为编译器以buffer作为自变量,调用string constructor。于是countChar的str参数会被绑定于此string临时对象上。当countChar返回,此临时对象会被自动销毁。这样的转换很方便,但也很危险(上面已经说到)。
但是这样的转换还是有条件的:只有当对象以bu value(传值)方式传递,或是当对象被传递给一个reference-to-const参数时,这些转换才会发会。如果对象被传递给一个reference-to-non-const参数,并不会发生此类转换。考虑这个函数:
void uppercasify(string& str);
在上一个(计算字符个数)例子中,我们可以成功地将一个字符数组传递给一个countChar,但是在这里,将一个字符数组交给uppercasify会导致调用失败:
char subtleBookPlug[] = "Effective C++";
uppercasify(subtleBookPlug);//错误!
不再有任何临时对象被产生出来以成全此函数的调用。
假设编译器为此产生了一个临时对象,然后此临时对象被传递给uppercasify,以便将其中的字符全部修改成大写。此函数的实元-subtleBookPlug-并未受到影响,只有以subtleBookPlug为本所产生的那个string临时对象受到影响。这当然不是程序员所企盼的结果。程序员将subtleBookPlug传递给uppercasify,就是希望subtleBookPlug被修改。当程序员期望“非临时对象”被修改,此时如果编译器针对“references-to-non-const”对象进行隐式转换,会允许临时对象被修改。这就是为什么C++语言禁止为non-const reference参数产生临时对象的原因。Reference-to-const参数不需要为此承担问题,因为此等参数由于const之故,无法被修改。
(2)隐式转换发生的条件:
(a)编译器原来就支持地转换:比如float型向int型转换,子类的对象(指针)向父类的对角(指针)转换,非const对象(指针)向const对象(指针)转换等等。
(b)当有类型转换操作符的时候。如果类型匹配且有必要,编译器会自动调用它。
(c)当类有一个参数个数为1的构造函数的时候。如果类型匹配有必要,编译器会自动调用它。
现在主要说明(b),(c)两点:
类型转换操作符,是一个拥有奇怪名字的member funtion:关键字operator之后加上一个类型名称。如下:
class Rational
{
public:
Rational(int x,int y):m_x(x),m_y(y){}
operator double()const;//将Rational转换为double.
private:
int m_x;
int m_y;
};
Rational::operator double()const //实现
{
return static_cast<double>(m_x)/m_y;
}
如果在main函数中这样调用:
Rational rat(1,2);
cout<<rat<<endl;//打印0.5
同于编译器发现不存在任何operator<<可以接受一个Rational类型,但它会想尽办法让函数调用成功。在本例中,编译器发现只要调用Rational::double操作符便可以将rat转换为double,调用动作便会成功。于是上述代码将rat以double输出。
当类有一个参数个数为1的构造函数的时候,也可能发生隐式类型转换。
考虑以下代码:
Template<class T>
class Array
{
public:
Array(int lowBound,int highBound);
Array(int size);
T& operator[](int index);
......
};
上述class的第一个constructor允许clients指定某个范围内的数组索。身为一个双自变量constructor,此函数没有资格成为类型转换函数。第二个constructor允许用户只指定数组的元素个数,便可以定义出Array
objects。它可以被用来作为一个类型转换函数,结果导致一些意外的结果。
例如:考虑一个用来对Array<int>对象进行比较的函数,以及一小段代码:
bool operator == (const Array<int>& lhs,const Array<int>& rhs);
Array<int> a(10);
Array<int> b(10);
......
//初始化
for(int i = 0;i < 10; ++i)
{
if( a == b[i]) //“a”应该是“a[i]”才对
{
do something ......
}
当试图将a的每一个元素拿来和b的对应元素比较时,当键入a时却意外地遗漏了下标。然而编译器却没有报错,原因是它看到一个operator ==,夹带着类型为Array<int>的自变量a和类型为int的自变量b[i],虽然没有这样的operator == 可以调用,但是编译器却注意到,只要调用Array<int> constructor(需要一个int作为自变量),它就可以将int转为Array<int> object,从而可以调用operator == (const Array<int>&
lhs,const Array<int>& rhs)。于是拿a的内容来和一个大小为b[i]的临时数组做比较,从而可能导致不可预料的结果。
(3)解决办法:
对于因类型转换操作符引起的最好办法就是提供转换的成员函数来代替转换操作符。如标准库中string类转换到char*时提供函数:c_str()。通过显式地调用成员函数而不是“默默地”调用转换操作符。
对于第二种情况说两种办法。第一是使用关键字explicit来修饰构造函数,如:
template<class T>
class Array
{
public:
......
explicit Array(int size);
......
};
这样这个构造函数便只能显式地调用了,上述if( a == b[i])语句便会报错,因为编译器不会把b[i]作为参数而调用Array(int size)这个构造函数,从而会因为“==”两边的类型不匹配而报错。
第二个办法是使用内部类。如下:
template<class T>
class Array
{
public:
class ArraySize
{
public:
ArraySize(int numElements):theSize(numElements){}
int size()const{ return theSize;}
private:
int theSize;
};
Array(int lowBound,int highBound);
Array(ArraySize size);//注意这个新的声明
......
};
在这里,把ArraySize嵌套放进Array内,用来修饰Array构造函数参数。
现在考虑当我们通过Array的“单自变量构造函数”定义一个对象时,会发生什么事情:
Array<int> a(10);
编译器被要求调用Array<int>class 中的一个自变量为int的构造函数,但其实并不存在这样的构造函数。编译器知道它能够将int自变量转换为一个临时的ArraySize对象,而该对象正是Array<int>构造函数需要的,所以编译器便执行了这样的转换。于是“以一个int自变量构造起一个Array对象”这个事实依然有效。再次考虑这段代码:
Array<int> a(10);
Array<int> b(10);
......
for(int i = 0;i < 10;++i)
if( a == b[i]) //"a"应该是“a[i]” 如今这形成了一个错误。
编译器需要一个类型为Array<int>的对象在“==”右手边,得以针对Array<int> 对象调用operator == ,但是此刻并没有“单一自变量,类型为int”这样的构造函数。此外,编译器不能考虑将一个int转换为一个临时性的ArraySize对象,然后再根据这个临时对象产生必要的Array<int>对象,因为那将调用两个用户制定转换行为(这是不允许的),一个将int转换为ArraySize,另一个将ArraySize转换为Array<int>。如此的转换程序是禁止的,所以编译器对以上代码发出错误消息。
(4)隐式转换与临时对象
首先声明一下,这里我们所讲的临时对象,并不是指一个短暂需要的对象(如这里的temp): int temp = a,a = b,b = temp 。C++真正的临时对象是不可见的---不会出现在你的源代码中。只要你产生了一个non-heap object而没有为它命名,便诞生了一个临时对象。此等匿名对象通常发生于两种情况:一是当隐式类型转换被施行起来以求函数调用能够成功;二是当函数返回对象的时候。这里主要讲第一种情况。看以下代码:
size_t countChar(const string& str,char ch);
char buffer[MAX_STRING_LEN];
char c;
//读入一个char和一个string
cin>>c>>setw>>(MAX_STRING_LEN)>>buffer;
cout<<"There are "<<countChar(buffer,c)<<"occurrences of the character"<<c<<" in "<<buffer<<endl;
看countChar的调用动作。其第一自变量是个char数组,但是相应的函数参数类型却是const string&。之所以会调用成功,是因为编译器以buffer作为自变量,调用string constructor。于是countChar的str参数会被绑定于此string临时对象上。当countChar返回,此临时对象会被自动销毁。这样的转换很方便,但也很危险(上面已经说到)。
但是这样的转换还是有条件的:只有当对象以bu value(传值)方式传递,或是当对象被传递给一个reference-to-const参数时,这些转换才会发会。如果对象被传递给一个reference-to-non-const参数,并不会发生此类转换。考虑这个函数:
void uppercasify(string& str);
在上一个(计算字符个数)例子中,我们可以成功地将一个字符数组传递给一个countChar,但是在这里,将一个字符数组交给uppercasify会导致调用失败:
char subtleBookPlug[] = "Effective C++";
uppercasify(subtleBookPlug);//错误!
不再有任何临时对象被产生出来以成全此函数的调用。
假设编译器为此产生了一个临时对象,然后此临时对象被传递给uppercasify,以便将其中的字符全部修改成大写。此函数的实元-subtleBookPlug-并未受到影响,只有以subtleBookPlug为本所产生的那个string临时对象受到影响。这当然不是程序员所企盼的结果。程序员将subtleBookPlug传递给uppercasify,就是希望subtleBookPlug被修改。当程序员期望“非临时对象”被修改,此时如果编译器针对“references-to-non-const”对象进行隐式转换,会允许临时对象被修改。这就是为什么C++语言禁止为non-const reference参数产生临时对象的原因。Reference-to-const参数不需要为此承担问题,因为此等参数由于const之故,无法被修改。
发表评论
-
c++操作符优先级总结
2013-12-03 14:47 798优先级从上到下依次递减,最上面具有最高的优先级,逗号操作符具有 ... -
Qt状态机实例
2013-12-03 14:01 1107#include <QApplication> ... -
C中的野指针
2013-08-30 16:11 1054讨论一 什么是野指针 ... -
STL学习(转)
2012-08-28 15:38 1446STL就是Standard Template Libr ... -
STL详解
2012-08-28 14:33 1757STL概述 STL的一个重要 ... -
c++的三种继承(转)
2012-08-23 18:47 1104http://blog.csdn.net/wang_lime ... -
MFC OpenGL标签云 (转)
2012-08-22 11:21 1265初识标签云是在去年年末,一看到这个应用我就特别感兴趣。还记 ... -
MFC中ADO方式操作数据库实例(转)
2012-08-22 11:12 2443连接ACCESS为例: //头文件 #pragma on ... -
派生类的构造函数(转)
2012-08-20 18:05 992派生类的数据成员由所 ... -
元算符重载时友元函数和成员函数的选择
2012-08-18 20:14 1418一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好 ... -
C++面试题(转)
2012-08-16 17:25 8211.是不是一个父类写了一个virtual 函数,如果子类覆盖它 ... -
8皇后问题c++的递归实现
2012-08-16 16:18 1499最近用C++递归形式实现了8皇后问题,可能效率有点低 #i ... -
c++实现的一些排序算法
2012-08-15 11:37 1394最近用c++简单实现了一些排序算法,记下来,以便以后用到 ... -
mfc 常用控件使用方法及常见数据类型转换
2012-04-18 20:31 2111最近做了几个mfc小程序,想把我们经常用到而又经常忘记的的小知 ...
相关推荐
总的来说,C++的数据类型转换是一门深奥的学问,熟练掌握各种转换方法是成为一名合格的C++程序员的关键。在编写程序时,应始终注意类型安全,避免不必要的类型转换,特别是那些可能导致数据丢失或错误的转换。通过...
C++ 数据类型转换 C++ 编程语言中,数据类型转换是非常重要的一方面。不同的数据类型之间可以相互转换,以满足不同的编程需求。在本文中,我们将详细介绍 C++ 数据类型之间的相互转换,包括基本数据类型、CString、...
C++ 数据类型转换 C++ 数据类型转换是指在不同的数据类型之间进行转换,以满足不同的应用场景和需求。在 C++ 中,数据类型转换可以分为两大类:隐式转换和显式转换。隐式转换是由编译器自动完成的,而显式转换则...
在C++编程中,数据类型转换是至关重要的概念,它允许程序员在不同数据类型之间进行灵活的操作。C++提供了多种方式来实现数据类型的转换,这使得我们能够在必要时改变变量的存储格式或处理精度。本篇文章将深入探讨...
在实际开发中,我们经常需要在C++和C#之间进行数据类型转换,以便于在不同的语言环境中进行数据交换。 在C++和C#中,数据类型是不同的,C++使用C语言的数据类型,而C#使用.NET Framework的数据类型。因此,在将C++...
C++常用数据类型使用转换详解
C++数据类型之间的转换源代码,介绍了使用C转换函数族,snprintf/sscanf和stringstream的使用方法。
C++中的数据类型转换方法标准c++MFC类型,归纳汇总。
在实际应用中,强制类型转换函数可以用于解决许多问题,例如将基本数据类型转换为其他类型、将基类指针转换为子类指针、将void指针转换为目标类型的指针等。但是,需要注意的是,强制类型转换函数可能会带来一些风险...
下面我们将详细探讨C++中的数据类型转换及其应用。 1. **隐式转换(Implicit Conversion)**:这是编译器自动进行的转换,例如,将较小的类型(如`int`)赋值给较大的类型(如`long`)时,或者在运算中不同类型的...
C++作为一种强大的面向对象编程语言,支持多种类型的转换机制,这些转换机制不仅能够帮助程序员处理数据类型之间的兼容性问题,还能确保程序的安全性和正确性。本文将详细介绍C++中的四种类型转换方式:C风格类型...
类型转换可以将一种数据类型转换为另一种数据类型,以便于不同的数据类型之间的交互和操作。本文将详细介绍C++中常见的类型转换,包括IP地址转换、CString类型转换、float、int、double类型转换、string类型转换等。...
#### C/C++数据类型的转换 在C/C++编程语言中,提供了多种数据类型以满足不同的编程需求,包括但不限于整型(`int`)、浮点型(`float`、`double`)、字符型(`char`)等基本类型,以及数组、结构体、共用体、枚举...
在C++编程中,数据类型转换是至关重要的,它允许我们根据需求在不同类型的值之间进行灵活的操作。这里我们将深入探讨几种主要的数据类型转换方法,包括字符串与整数、浮点数之间的转换,以及整数、浮点数转换为字符...
当我们需要在XML文档和C++数据结构之间进行数据交换时,就需要进行XML与C++数据结构的互相转换。这个过程在进程间通信(IPC)和模块间通信中尤其重要,因为它能够降低不同组件之间的耦合度,提高代码的可维护性和...
综上所述,虽然C++Builder和Delphi的数据类型在名称和实现上有所不同,但它们在功能和用途上有着密切的联系,开发者可以根据具体需求在两种环境之间进行灵活转换。了解这些类型的基本概念及其跨平台的对应关系,对于...
在C++编程中,数据类型转换是非常常见的操作,它有助于程序员更加灵活地处理各种数据。本文将详细介绍C++中几种常见数据类型之间的转换方法,帮助读者更好地理解和掌握这些技巧。 #### 标题:C++常用变量类型的转换...
类型转换运算符是C++中用于显式类型转换的关键工具,它们允许程序员在需要时明确地转换数据类型。本文将深入探讨C++中的类型转换运算符,包括它们的使用场景、语法和一些实际应用示例。 类型转换运算符是C++中处理...
c/c++ Windows移植到LINUX 的数据类型转换总结,都在WinToLinux.h文件中,需要时直接引入此头文件即可,很实用。