如何将一个对象赋值给指定类型的数据?

用转换构造函数可以将一个指定类型的数据转换为类的对象。但是不能反过来将一个类的对象转换为一个其他类型的数据(例如将一个Complex类对象转换成double类型数据)。

C++提供类型转换函数(type conversion function)来解决这个问题。类型转换函数的作用是将一个类的对象转换成另一类型的数据。如果已声明了一个Complex类,可以在Complex类中这样定义类型转换函数:
    operator double( )
    {
        return real;
    }
函数返回double型变量real的值。它的作用是将一个Complex类对象转换为一个double型数据,其值是Complex类中的数据成员real的值。请注意,函数名是operator double,这点是和运算符重载时的规律一致的(在定义运算符“+”的重载函数时,函数名是operator +)。

类型转换函数的一般形式为:
    operator 类型名( )
    {
        实现转换的语句
    }
在函数名前面不能指定函数类型,函数没有参数。其返回值的类型是由函数名中指定的类型名来确定的。类型转换函数只能作为成员函数,因为转换的主体是本类的对象。不能作为友元函数或普通函数。

从函数形式可以看到,它与运算符重载函数相似,都是用关键字operator开头,只是被重载的是类型名。double类型经过重载后,除了原有的含义外,还获得新的含义(将一个Complex类对象转换为double类型数据,并指定了转换方法)。这样,编译系统不仅能识别原有的double型数据,而且还会把Complex类对象作为double型数据处理。

那么程序中的Complex类对具有双重身份,既是Complex类对象,又可作为double类型数据。Complex类对象只有在需要时才进行转换,要根据表达式的上下文来决定。转换构造函数和类型转换运算符有一个共同的功能:当需要的时候,编译系统会自动调用这些函数,建立一个无名的临时对象(或临时变量)。

[例10.9] 使用类型转换函数的简单例子。
#include <iostream>
using namespace std;
class Complex
{
public:
   Complex( ){real=0;imag=0;}
   Complex(double r,double i){real=r;imag=i;}
   operator double( ) {return real;} //类型转换函数
private:
   double real;
   double imag;
};
int main( )
{
   Complex c1(3,4),c2(5,-10),c3;
   double d;
   d=2.5+c1;//要求将一个double数据与Complex类数据相加
   cout<<d<<endl;
   return 0;
}
对程序的分析:
1) 如果在Complex类中没有定义类型转换函数operator double,程序编译将出错。因为不能实现double 型数据与Complex类对象的相加。现在,已定义了成员函数 operator double,就可以利用它将Complex类对象转换为double型数据。请注意,程序中不必显式地调用类型转换函数,它是自动被调用的,即隐式调用。在什么情况下调用类型转换函数呢?编译系统在处理表达式 2.5 +cl 时,发现运算符“+”的左侧是double型数据,而右侧是Complex类对象,又无运算符“+”重载函数,不能直接相加,编译系统发现有对double的重载函数,因此调用这个函数,返回一个double型数据,然后与2.5相加。

2) 如果在main函数中加一个语句:
    c3=c2;
请问此时编译系统是把c2按Complex类对象处理呢,还是按double型数据处理?由于赋值号两侧都是同一类的数据,是可以合法进行赋值的,没有必要把c2转换为double型数据。

3) 如果在Complex类中声明了重载运算符“+”函数作为友元函数:
    Complex operator+ (Complex c1,Complex c2)//定义运算符“+”重载函数
    {
        return Complex(c1.real+c2.real, c1.imag+c2.imag);
    }
若在main函数中有语句
    c3=c1+c2;
由于已对运算符“+”重载,使之能用于两个Complex类对象的相加,因此将c1和c2按Complex类对象处理,相加后赋值给同类对象c3。如果改为
    d=c1+c2; //d为double型变量
将c1与c2两个类对象相加,得到一个临时的Complex类对象,由于它不能赋值给double型变量,而又有对double的重载函数,于是调用此函数,把临时类对象转换为double数据,然后赋给d。

从前面的介绍可知,对类型的重载和对运算符的重载的概念和方法都是相似的,重载函数都使用关键字operator。因此,通常把类型转换函数也称为类型转换运算符函数,由于它也是重载函数,因此也称为类型转换运算符重载函数(或称强制类型转换运算符重载函数)。

假如程序中需要对一个Complex类对象和一个double型变量进行+,-,*,/等算术运算,以及关系运算和逻辑运算,如果不用类型转换函数,就要对多种运算符进行重载,以便能进行各种运算。这样,是十分麻烦的,工作量较大,程序显得冗长。如果用类型转换函数对double进行重载(使Complex类对象转换为double型数据),就不必对各种运算符进行重载,因为Complex类对象可以被自动地转换为double型数据,而标准类型的数据的运算,是可以使用系统提供的各种运算符的。

[例10.10] 包含转换构造函数、运算符重载函数和类型转换函数的程序。先阅读以下程序,在这个程序中只包含转换构造函数和运算符重载函数。
#include <iostream>
using namespace std;
class Complex
{
public:
   Complex( ){real=0;imag=0;}  //默认构造函数
   Complex(double r){real=r;imag=0;}//转换构造函数
   Complex(double r,double i){real=r;imag=i;}//实现初始化的构造函数
   friend Complex operator + (Complex c1,Complex c2); //重载运算符“+”的友元函数
   void display( );
private:
   double real;
   double imag;
};
Complex operator + (Complex c1,Complex c2)//定义运算符“+”重载函数
{
   return Complex(c1.real+c2.real, c1.imag+c2.imag);
}
void Complex::display( )
{
   cout<<"("<<real<<","<<imag<<"i)"<<endl;
}
int main( )
{
   Complex c1(3,4),c2(5,-10),c3;
   c3=c1+2.5; //复数与double数据相加
   c3.display( );
   return 0;
}
注意,在Visual C++ 6.0环境下运行时,需将第一行改为#include <iostream.h>,并删去第2行,否则编译不能通过。

对程序的分析:
1) 如果没有定义转换构造函数,则此程序编译出错。

2) 现在,在类Complex中定义了转换构造函数,并具体规定了怎样构成一个复数。由于已重载了算符“+”,在处理表达式c1+2.5时,编译系统把它解释为
    operator+(c1, 2.5)
由于2.5不是Complex类对象,系统先调用转换构造函数Complex(2.5),建立一个临时的Complex类对象,其值为(2.5+0i)。上面的函数调用相当于
    operator+(c1, Complex(2.5))
将c1与(2.5+0i) 相加,赋给c3。运行结果为
    (5.5+4i)
3) 如果把“c3=c1+2.5;”改为c3=2.5+c1; 程序可以通过编译和正常运行。过程与前相同。

从中得到一个重要结论,在已定义了相应的转换构造函数情况下,将运算符“+”函数重载为友元函数,在进行两个复数相加时,可以用交换律。

如果运算符函数重载为成员函数,它的第一个参数必须是本类的对象。当第一个操作数不是类对象时,不能将运算符函数重载为成员函数。如果将运算符“+”函数重载为类的成员函数,交换律不适用。

由于这个原因,一般情况下将双目运算符函数重载为友元函数。单目运算符则多重载为成员函数。

4) 如果一定要将运算符函数重载为成员函数,而第一个操作数又不是类对象时,只有一个办法能够解决,再重载一个运算符“+”函数,其第一个参数为double型。当然此函数只能是友元函数,函数原型为
    friend operator+(double, Complex &);
显然这样做不太方便,还是将双目运算符函数重载为友元函数方便些。

5) 在上面程序的基础上增加类型转换函数:
    operator double( ){return real;}
此时Complex类的公用部分为:
   public:
   Complex( ){real=0;imag=0;}
   Complex(double r){real=r;imag=0;}  //转换构造函数
   Complex(double r,double i){real=r;imag=i;}
   operator double( ){return real;}//类型转换函数
   friend Complex operator+ (Complex c1,Complex c2); //重载运算符“+”
   void display( );
其余部分不变。程序在编译时出错,原因是出现二义性。

时间: 2024-08-11 07:40:30

如何将一个对象赋值给指定类型的数据?的相关文章

C#把对象类型转化为指定类型,转化失败时返回该类型默认值

/// <summary> ///通用类型扩展方法类 /// </summary> public static class ObjectExtensions { /// <summary> ///把对象类型转化为指定类型,转化失败时返回该类型默认值 /// </summary> /// <typeparam name="T"> 动态类型 </typeparam> /// <param name="v

将表单序列化类型的数据转化成对象的处理(允许对象中包含对象)

表单序列化类型的数据是指url传递的数据的格式,形如"key=value&key=value&key=value"这样的key/value的键值对.一般来说使用jQuery的$.fn.serialize函数能达到这样的效果.如何将这样的格式转化为对象? 我们知道使用jQuery的$.fn.serializeArray函数得到的是一个如下结构的对象 [ { name: "startTime" value: "2015-12-02 00:00:

2015/12/14 - 对象赋值问题 与 IE8hack

今天在工作中发现以前没有注意到地方,那就是如果将一个对象通过赋值运算符"="赋值给另一个变量或对象时,那么作为接收值的变量或对象中保存的并不是这个对象的值或数据,而只是保存指向这个对象的this指针而已. 例如: var x = {'a':1} var y = x; // 变量y中保存的并不是对象x的内容,而是一个this指针,其源头任然是对象x 所以这样,一旦我们对变量y的内容进行了更改,那么作为源头的x对象也将发生变化. 1 var x = {'a':1} 2 var y = x;

无法从使用方法中推导出方法... 的类型实參,请尝试显式指定类型实參

这个问题,网上基本没得什么解决方法,事实上都是编程习惯造成的,在程序的世界里,用户自己命名必须规范,唯一,与系统框架提供的对象名称分开.否则将会产生非常多,标题问题.以上问题,非常多都是没有确切 指定,多空间命名的时候,建立了多个一样的对象名,而在统一地方使用对象,没有明白指定,哪个空间对象,就会报以上错误:比如 空间一 using System; namespase Models { public class orderby {} } 空间二 using System; namespase B

反射给对象赋值——类型转换

文章转自: http://blog.csdn.net/xiaohan2826/article/details/8536074 反射给对象赋值遇到的问题--类型转换 发布时间:2012-10-25 10:49浏览次数:225 给一个对象属性赋值可以通过PropertyInfo.SetValue()方式进行赋值,但要注意值的类型要与属性保持一致. 创建对象实例的两种方法: 1. 1 var obj = Assembly.Load("AssemblyName").CreateInstance

C++ 类继承与对象赋值 情况下 成员变量的覆盖 浅析

[摘要] 类的继承以及对象的赋值会带来成员变量的相互传递.这里详细讨论了,类间继承带来的成员变量的传递采用覆盖原则,采用函数级的成员变量的取值:对象赋值带来的成员变量的传递采用,实函数采用数据类型的实函数,虚函数采用赋值源的虚函数,成员变量采用赋值源的成员变量,其实也是函数级的成员变量. [正文] 在类继承中,成员变量存在覆盖的情况,成员函数则存在隐藏和覆盖以及重载的情况.在类继承中,公有继承会导致公有成员变量的覆盖,从而使得成员函数的调用出现各种结果. [代码示例 01] #include<i

File类——renameTo()将文件夹内的所有指定类型文件 移动到另一个文件夹内

* 由于   张孝祥-7K月薪面试题破解之一_交通灯管理系统视频教程 文件夹下 的视频文件都存放在每个子文件夹中 * 需求:将所有视频文件全部移动到  张孝祥-7K月薪面试题破解之一_交通灯管理系统视频教程文件夹下  原来存放视频的子文件夹删除 public class moveFiles { public static void main(String[] args) { // TODO Auto-generated method stub File f = new File("D:\\Bai

递归获取当前节点全部指定类型的子节点

在线预览 方法 使用nodeType判断类型,在allChildNodes方法内建立递归函数将allCN封装在方法内. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> p{ color: red; } span{ color: blue; }

获取指定路径下指定类型的文件名称,并返回可用的新名称

检查磁盘上指定目录是否已经存在同名文件(本代码是检查.jpg文件类型),存在三种情况: 1:不存在,返回查询的名称 如:输入abc,返回abc 2:存在一个名称相同的文件,返回"预定义的名称+当前日期+001"的新名称 如:存在一个叫abc.jpg的文件,输入abc,返回abc20101227001 3:存在多个前缀名相同的文件,则返回比编号最大的文件大一个编号的名称 如:存在abc.jpg,abc20101227001,abc20101227002,-,abc201012270023