随笔 - 181  文章 - 15  trackbacks - 0
<2009年1月>
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

常用链接

留言簿(1)

随笔分类

随笔档案

My Tech blog

搜索

  •  

最新评论

阅读排行榜

评论排行榜

在阅读类型转换之前,还是先看一下关键字explicit(显式)
书上的例子中的类名叫做Stack,这样总感觉有些误解,因为栈这个概念已经在我们的脑海中先入为主了,容易形成思维定式.那么我写一个和其他任何概念都无关的例子:
class MyClass
{    
    
private:
    
int _number;
    
public:
    MyClass(
int number)
    {
        _number
=number;
    }
};
上面的类很普通,没什么特别的.我们可以这样创建这个类的对象:
int main()
{
    MyClass instance
=5;
}
这就比较有意思了,c++还能这样写,我以前的确没有见过.那么explicit关键字的作用就是不让你这样写,如果你这样写了,编译器就会给你一个错误提示.现在改造一下MyClass
class MyClass
{    
    
private:
    
int _number;
    
public:
    
explicit MyClass(int number)
    {
        _number
=number;
    }
};
main函数不变的情况下,编译器会这样提示你:
Explicit.cpp: In function ‘int main()’:
Explicit.cpp:14: 错误: conversion from ‘int’ to non-scalar type ‘MyClass’ requested
这样,就只能这样写了:
MyClass instance(5);
好了,下面开始阅读类型转换的部分.
1 static_cast
这个操作符的执行过程可以被认为是:它创建了一个新的对象,然后用要转换的值去初始化这个新对象.这个转换只有当一个类型转换被声明过才能执行.
首先是一个简单的例子:
//一个简单的类型转换
   int valueToBeConverted=int();
   
using namespace std;
   cout
<<static_cast<float>(valueToBeConverted)<<"\n";
很像其他语言中的显式类型转换.那么对于我自己的类如何进行转换呢?可以看一下下面的这个例子:
#include <iostream>

class MyClass2
{
   
public:
    
int IntMember1;
   MyClass2()
   {
      IntMember1
=1;
   }
};
class MyClass1
{
   
public:
   
int IntMember1;
   
virtual void  f()
   {
       std::cout
<<IntMember1<<"\n";
   }
   
explicit MyClass1(MyClass2 instance)
   {
       IntMember1
=instance.IntMember1;
   }
};
int main()
{
   MyClass2 mc2Instance;
   MyClass1 mc1Instance
=static_cast<MyClass1>(mc2Instance);
   mc1Instance.f();
}
注意看上面的粗体字explicit.如果没有explict对于构造函数的修饰,那么万全可以简单爽快的这么写:
MyClass1 mc1Instance=mc2Instance;
换句话说,如果你想让别人写代码的时候不关心类型,舒舒服服的写出你认为不安全的代码,那么你就去掉explicit,如果你想让别人在写代码的时候,让那些不安全的类型转换变得更加"显眼"一些,那么你就按上面这样写.然后让编译器狠狠的给他们一个警告.
2 dynamic_cast
This operator enables you to downcast a polymorphic type to its real static type. This is
the only cast that is checked at runtime. Thus, you could also use it to check the type of a
polymorphic value.

这个运算符能够让你把一个多态的类型转换成它的真实的静态类型.这是唯一的在运行时进行检验的转换方法.所以你同样需要在转换之前检验多态值的类型.
首先dynamic_cast只能够用于指针或者引用.否则编译器会告诉你类似这样的错误:
 无法将 ‘scInstance’ 从类型 ‘SubClass’ 动态转换到类型 ‘class BaseClass’ (target is not pointer or reference)
这里使用书中的例子:
 
class Car;         // 至少拥有一个抽象函数的抽象类
   class Cabriolet : public Car {
       
   };
   
class Limousine : public Car {
       
   };
   
void f(Car* cp)
   {
       Cabriolet
* p = dynamic_cast<Cabriolet*>(cp);
       
if (p == NULL) {
           
//p并非Cabriollet类型
           
       }
   }

In this example, f() contains a special behavior for objects that have the real static type
Cabriolet. When the argument is a reference and the type conversion fails,
dynamic_cast throws a bad_cast exception (bad_cast is described on page 26).
Note that from a design point of view, it it always better to avoid such type-dependent
statements when you program with polymorphic types.
当参数是一个引用并且类型转换失败的时候,dynamic_cast会抛出一个bad_cast异常.值得注意的是,从设计的角度来说,通常在进行多态类型的程序编写时,应该避免这样的类型依赖.
3 const_cast
This operator adds or removes the constness of a type. In addition, you can remove a
volatile qualification. Any other change of the type is not allowed.
这个操作符添加或除去一个类型的常量化(特性).另外,你可以除去一个变量变化的能力.任何对于这个类型变量的变化都将不被允许.
让常量可修改的例子:
class MyClass
{
    
public:
        
int MemberValue;
        
void showValue()
        {
            cout
<<"My Value is"<<MemberValue<<"\n";
        }
        MyClass()
        {
            MemberValue
=1;
        }    
};
int main()
{
    
const MyClass myValue;
    MyClass 
*ptr=const_cast<MyClass*>(&myValue);
    ptr
->MemberValue=100;
    ptr
->showValue();
}
上面的例子只是将一个const变得可以修改了,但是注意到书中的这样一句:
In addition, you can remove a
volatile qualification. Any other change of the type is not allowed.
似乎还可以将一个可变量转换为非可变的,这里没有查到相关资料,也许书的后面会有相应解释,所以这里先放一放.
4 reinterpret_cast
这个比较有趣,支持不兼容类型之间的转换.以下是例子:
#include <iostream>
using namespace std;
class ClassA
{
    
public:
    
int Value1;
    
int Value2;
    
int Value3;
    
void showValue()
    {
        cout
<<Value1<<","<<Value2<<","<<Value3<<"\n";
    }
};
class ClassB
{
    
public:
    
int Value1;
    
int Value2;
    
int Value3;
    ClassB()
    {
        Value1
=1;
        Value2
=2;
        Value3
=3;
    }
};
int main()
{
    ClassB 
*b=new ClassB();
    ClassA 
*a=reinterpret_cast<ClassA*>(b);
    a
->showValue();
}
同样,这种转换对于非基本类型来说,仍然只能支持指针和引用.
这些运算符的优点就是他们明确了类型转换的意图,并且能够让编译器获取更多的信息来了解这些类型转换的原因,然后当这些转换操作越过他们的职能的时候,编译器会报告错误.
另外需要注意的是,这些类型转换都只能接受一个参数.看下面的例子:
    static_cast<Fraction>(15,100)                   
上面不会产生你想要的结果.这里的逗号并不是用来连接两个参数的,而是作为逗号运算符出现,这里15会被舍弃,而采用100作为参数构造Fraction.
所以还是需要采用下面的方法才合适:
    Fraction(15,100)                             





posted on 2007-06-17 14:56 littlegai 阅读(250) 评论(0)  编辑 收藏 引用 所属分类: 我的读书笔记

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理