- 浏览: 41979 次
- 性别:
- 来自: 大连
最新评论
(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 793优先级从上到下依次递减,最上面具有最高的优先级,逗号操作符具有 ... -
Qt状态机实例
2013-12-03 14:01 1100#include <QApplication> ... -
C中的野指针
2013-08-30 16:11 1049讨论一 什么是野指针 ... -
STL学习(转)
2012-08-28 15:38 1441STL就是Standard Template Libr ... -
STL详解
2012-08-28 14:33 1749STL概述 STL的一个重要 ... -
c++的三种继承(转)
2012-08-23 18:47 1088http://blog.csdn.net/wang_lime ... -
MFC OpenGL标签云 (转)
2012-08-22 11:21 1264初识标签云是在去年年末,一看到这个应用我就特别感兴趣。还记 ... -
MFC中ADO方式操作数据库实例(转)
2012-08-22 11:12 2440连接ACCESS为例: //头文件 #pragma on ... -
派生类的构造函数(转)
2012-08-20 18:05 989派生类的数据成员由所 ... -
元算符重载时友元函数和成员函数的选择
2012-08-18 20:14 1412一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好 ... -
C++面试题(转)
2012-08-16 17:25 8171.是不是一个父类写了一个virtual 函数,如果子类覆盖它 ... -
8皇后问题c++的递归实现
2012-08-16 16:18 1495最近用C++递归形式实现了8皇后问题,可能效率有点低 #i ... -
c++实现的一些排序算法
2012-08-15 11:37 1389最近用c++简单实现了一些排序算法,记下来,以便以后用到 ... -
mfc 常用控件使用方法及常见数据类型转换
2012-04-18 20:31 2099最近做了几个mfc小程序,想把我们经常用到而又经常忘记的的小知 ...
相关推荐
C++ 到 C# 数据类型转换 在软件开发中,数据类型转换是一个非常重要的步骤,特别是在使用不同的编程语言时。C++ 和 C# 是两种非常流行的编程语言,它们之间的数据类型转换是非常必要的。本文将详细介绍 C++ 到 C# ...
本项目"TypeByte@2019_C#_C++_C数据类型转换时间戳转换_"显然是针对C#、C++和C这三种编程语言,提供了一种解决方案来实现数据类型的互转以及时间戳的转换。 首先,让我们深入探讨一下C#中的数据类型转换。C#是一门...
C++ 数据类型转换 C++ 编程语言中,数据类型转换是非常重要的一方面。不同的数据类型之间可以相互转换,以满足不同的编程需求。在本文中,我们将详细介绍 C++ 数据类型之间的相互转换,包括基本数据类型、CString、...
C++ 数据类型转换 C++ 数据类型转换是指在不同的数据类型之间进行转换,以满足不同的应用场景和需求。在 C++ 中,数据类型转换可以分为两大类:隐式转换和显式转换。隐式转换是由编译器自动完成的,而显式转换则...
在实际开发中,我们经常需要在C++和C#之间进行数据类型转换,以便于在不同的语言环境中进行数据交换。 在C++和C#中,数据类型是不同的,C++使用C语言的数据类型,而C#使用.NET Framework的数据类型。因此,在将C++...
C++常用数据类型使用转换详解
C++中的数据类型转换方法标准c++MFC类型,归纳汇总。
在实际应用中,强制类型转换函数可以用于解决许多问题,例如将基本数据类型转换为其他类型、将基类指针转换为子类指针、将void指针转换为目标类型的指针等。但是,需要注意的是,强制类型转换函数可能会带来一些风险...
下面我们将详细探讨C++中的数据类型转换及其应用。 1. **隐式转换(Implicit Conversion)**:这是编译器自动进行的转换,例如,将较小的类型(如`int`)赋值给较大的类型(如`long`)时,或者在运算中不同类型的...
C++作为一种强大的面向对象编程语言,支持多种类型的转换机制,这些转换机制不仅能够帮助程序员处理数据类型之间的兼容性问题,还能确保程序的安全性和正确性。本文将详细介绍C++中的四种类型转换方式:C风格类型...
#### C#与C++数据类型的对应 在进行C#与C++之间的数据类型转换时,通常需要考虑以下几种情况: 1. **基本数据类型**:例如整型、浮点型等。 2. **指针与引用**:在C++中广泛使用的指针类型,在C#中主要通过引用(`...
在C++编程语言中,类的转换是一种重要的特性,它允许程序员定义类对象与内置数据类型之间以及不同自定义类之间的转换方式。这种转换通常分为两种类型:转换构造函数和成员转换函数,这两种方法都遵循C++的隐式类型...
在C++编程语言中,类型转换是至关重要的概念,它允许程序员在不同数据类型之间进行操作。本资源“vc.zip”包含了一份关于C++类型转换的详细文档“vc.doc”,涵盖了从基本数据类型到复杂类型的转换方法。下面,我们将...
类型转换可以将一种数据类型转换为另一种数据类型,以便于不同的数据类型之间的交互和操作。本文将详细介绍C++中常见的类型转换,包括IP地址转换、CString类型转换、float、int、double类型转换、string类型转换等。...
在C++编程中,数据类型转换是至关重要的,特别是在处理字符串时。本篇文章将全面探讨C++中如何将各种字符串类型转换为其他类型,并提供一些常见的转换实例。 首先,我们来了解一下可以转换的字符串类型:`char *`、...
#### C/C++数据类型的转换 在C/C++编程语言中,提供了多种数据类型以满足不同的编程需求,包括但不限于整型(`int`)、浮点型(`float`、`double`)、字符型(`char`)等基本类型,以及数组、结构体、共用体、枚举...
当我们需要在XML文档和C++数据结构之间进行数据交换时,就需要进行XML与C++数据结构的互相转换。这个过程在进程间通信(IPC)和模块间通信中尤其重要,因为它能够降低不同组件之间的耦合度,提高代码的可维护性和...
在C++编程中,数据类型转换是非常常见的操作,它有助于程序员更加灵活地处理各种数据。本文将详细介绍C++中几种常见数据类型之间的转换方法,帮助读者更好地理解和掌握这些技巧。 #### 标题:C++常用变量类型的转换...