科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件在可管理C++中封装值类型 (2)

在可管理C++中封装值类型 (2)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在可管理C++中封装值类型 (2)

作者:李阳编译 来源:赛迪网 2007年11月16日

关键字: 封装值类型 C++ Linux

  • 评论
  • 分享微博
  • 分享邮件

封装一个值的类别就是把值放到一个临时对象(这个对象是System::Object继承类的实例,存于垃圾收集堆)中,然后再把临时对象的地址传递给方法调用。原有变量中所有的东西都被拷入临时对象中,这个对象提供WriteLine()需要的所有功能。__box关键字意味着值类型和可管理类型都适合于基本类库提供的所有服务。

封装的替代办法

装箱允许你在期待指向可管指针的基本类库的方法中使用值类型和可管理类型。这自然产生了一个问题:在值类型和可管理类型中究竟有什么区别?可管理类型存于垃圾收集堆中,并且被运行时间所管理。下面是一个例子:

__gc class Foo
{
  // internals omitted
};

// ...
Foo* f = new Foo();

FOO类是可管理类型。你不能在堆栈上创建Foo f2;这样的实例:

如果你已经有一个类(也许是从以前的.net程序中获得),它一定不是一个可管理类型。它没有_gc关键字。当然,你可以加上关键字(假设类符合成为一个可管理类型的所有条件),但接下来你要找到所有创建类实例的地址,还有保证他们是在堆上创建的实例,比如:

OldClass* poc = new OldClass(); //maybe some parameters 
                                //to the constructor

你要记住,在代码中调用类方法的每一处,都要把.改为->。保持原来的类型,这样你可以按照你的意愿在堆栈或未管理的堆上分配实例:

class notmanaged
{
private:
  int val;
public:
  notmanaged(int v) : val(v) {};
};

// ...
  notmanaged nm(4);
  notmanaged *p = new notmanaged(5);

这并不难:这就是还没发布加入可管理扩展的Visual C++ .NET版本之前,C++的样子。如果你想把那些实例的其中一个传递给原来的WriteLine():

Console::WriteLine("notmanaged holds  {0}",nm);

你会得到和以前一样的错误信息:WriteLine() 使用老式风格类时并不比使用整数时过。你会想“我学到了一个新关键字,我知道该怎么做了”。

Console::WriteLine("notmanaged holds  {0}",__box(nm));

这会给你带来更模糊的信息"只有值类型能被装箱",未管理不是一种值类型吗?它的确不是可管理类型,但是它不是从基本类System::ValueType继承下来的(这些是有必要装箱的)。现在,有一个易用的值关键字,能够让类继承System::ValueType并可以被封装,但基于类和结构的考虑我并不认为封装是明智之举。你不会想让类或结构中的数据都被输出到屏幕上。你想对你的类被字符串来表示的方式进行些控制——说得明确一点,以System::String的方式。换言之,你想写个函数,以便你能保留对你的类的行为的控制。那么为何不加一个ToString() 方法?

class notmanaged
{
private:
  int val;
public:
  notmanaged(int v) : val(v) {};
  String* ToString() {return __box(val)->ToString();}
};
// ...
notmanaged nm(4);
Console::WriteLine("notmanaged holds  {0}",nm.ToString());
notmanaged *p = new notmanaged(5);
Console::WriteLine("notmanaged pointer has {0}",p->ToString());

注意在ToString()方法中对__box 的灵活运用,以使它能够返回一个指向可管理类型System::String的指针。你能够很容易的将这个方法扩展到一个有多种成员变量的类中。当然,你能够随心所欲的命名方法,但是将其命为ToString能够帮助其他的.net程序员,因为这个名字在基本类库中意味着一个以System::String表达类内部的方法。

拆箱

但现在为止,你仅仅看到了_box关键字在临时环境中的应用,只是传递给一个方法。但是你可以创建一个生命期很长的指向可管理类型的指针,比如:

__box int* bx = __box(x);

记住这是一个复制版很重要。若你改变了它,其他的原有部分并不会变。以下的四行:

__box int* bx = __box(x);
*bx = 7;
Console::WriteLine("bx is {0}", bx);
Console::WriteLine("x is still {0}", __box(x));

产生如下结果:

bx is 7
x is still 3

如果你想把复制版改回原先的状况,只需要废除指针:

x = *bx;

则x会是你给装箱的复制版所赋的新值(在此例中是7)。

小结

只为了将易于处理的整数输出到屏幕上,我们就走了这么长的一段路。理解可管理类型和未被管理类型间的区别对你在清楚地使用可管理C++很重要。将未被管理类型装箱是将其转化为可管理指针的有效办法,但当未被管理类型是一个类的时候,记住你能够控制它,并且能够创建可管理指针,无论如何你选择这样做——还有一个叫做ToString的成员函数是一种卓越的解决之道。不用任何关键字你就能够拆箱---只是将值取出来。那么就不要让讨厌的错误破坏了你探索基本类库的乐趣!

查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章