【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 1993|回复: 1

[转]windows8开发简易教程(下)

[复制链接]
发表于 2012-8-3 13:37:48 | 显示全部楼层 |阅读模式
【windows8开发五】异步编程之Concurrency::create_async(C++)
这一篇文章会继续讲到异步处理,在上一篇文章中提到过,Concurrency::task支持异步处理,但是由于它不支持跟其他语言的交互,所以如果希望开发的组件能在其他语言,比如C#,Javascript,VB中使用的话,就需要多语言交互的API,它就是Concurrency::create_async。
       我们把Concurrency::task和Concurrency::create_async两种处理方式对照来看。
       如果我们的组件本身以及调用方都只可能是C++的话,我们会使用Concurrency::task来实现异步处理。因为它更直接,所以效率也更高。假设也许我们会设计如下这样的异步处理方法:
  1. Concurrency::task<vector<int>> GetFileContentAsync() {
  2. return Concurrency::task<vector<int>>([]() {
  3. // 异步处理
  4. });
  5. }
复制代码
那么反之,如果组件会在C++之外的语言中使用,我们就应该使用Concurrency::create_async方法,所以上面使用Concurrency::task的处理我们会改为使用Concurrency::create_async:
  1. IAsyncOperation<IVector<int>^>^ GetFileContentAsync() {
  2. return Concurrency::create_async([]() ->IVector<int>^ {
  3. // 异步处理
  4. });
  5. }
复制代码
是不是有点难理解,让我来解释下上面的异步处理方式吧。
WinRT提供了4种异步处理的接口方式,
1. Windows::Foundation::IAsyncAction : 无返回值,无处理进度报告
2. Windows::Foundation::IAsyncActionWithProgress<TProgress>:无返回值,有处理进度报告
3. Windows::Foundation::IAsyncOperation<TResult>:有返回值,无处理进度报告
4. Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress>:有返回值,有处理进度报告
        
     而Concurrency::create_async方法的参数是个Lambda表达式,也就是匿名函数指针。而create_async能根据Lambda表达式中的参数和返回值来决定4种接口中的一种作为返回类型。现在可以看出上面的异步处理中,create_async参数Lambda表达式(匿名函数)是无参数的,所以它就是无处理进度报告的,而Lambda表达式的返回值类型为IVector<int>^,所以create_async就是有返回值得。综合来看上述异步处理就应该是有返回值,无处理进度报告对应的IAsyncOperation<TResult>。

如果想参照create_async的使用实例,可以参考windows8开发简易教程(上)其中就有返回值为IAsyncOperationWithProgress<TResult, TProgress>的实例。

【windows8 开发六】异步编程之Promise(Javascript)

Javascript是一种单线程语言,一旦运行一些耗时的处理,其他一切处理都会被阻塞。所以在Javascript中,异步处理显得尤为重要。由于Javascript只会运行在一个线程中,它的异步模式本质是把一些耗时的处理推迟到未来的某个时间点来运行,也正因如此,在Javascript的代码中往往充满了很多的回调处理。
Windows Runtime中提供了Promise接口,利用这个接口可以很方便的实现异步处理和回调。
看一段代码:
  1. var test = asyncFunc().then(
  2. function (result) {
  3. console.log("async completed and get result");
  4. },
  5. function (error) {
  6. console.log("error");
  7. },
  8. function (progress) {
  9. console.log("get progress");
  10. }
  11. );
复制代码
这里先解释以下promise.then方法,定义如下:
  1. promise.then(onComplete, onError, onProgress)
复制代码
onComplete为asyncFunc成功后执行的回调函数,OnError为asyncFunc发生错误时的回调处理,onProgress为asyncFunc中每次进行进度报告时的回调处理。

promise.then算是promise最常用的一个方法,此外还有一个方法是promise.done,它的定义跟then完全相同,如下所示:
  1. promise.done(onComplete, onError, onProgress)
复制代码
它们之间有何区别呢?目前发现两点:
1.then支持延续任务调用方式(Continuation tasks),而done不支持

比如then可以这样用,而done不可以:
  1. func().then().then().then()
复制代码
2. then会捕获未处理的异常然后把错误状态作为返回值返回,而done则会把异常直接抛出


windows8开发简易教程(上) 这篇文章中有promise.then方法的具体使用实例,大家可以参考下。
 楼主| 发表于 2012-8-3 13:43:45 | 显示全部楼层
【windows8开发七】C++/CX 深入浅出

关于C++ /CX:
C++ 0x/11是目前最新的C++标准库,而C++ /CX其实是微软在Win8开发平台下,对C++语言的一种扩展,它跟C++ 0x/11以及C++ /CLR是完全不同的东西。C++ /CLR是微软为了C++能在.Net下运行,针对CLR,虽然也是对C++的扩展,但它编译后是托管于CLR的,属于Managed C++。而C++ /CX则属于Native C++,它不使用CLR也没有垃圾回收机制。虽然C++ /CX有些新语法特性是直接从/CLR借鉴过来的,但是从底层实现上来看,它们是完全不同的两种扩展。
本文会简单介绍C++ /CX在语法上的一些扩展。


1.值类型value和引用类型ref
value和ref都是用来定义class的,所以有如下的语法:
  1. ref class Object{};
  2. value class Object{};
复制代码
两者有什么不同?其实引用类型ref类似于Java里面的引用概念,而值类型value就是我们通常理解的C++类型。那又为什么要增加这样的关键字来进行区分呢?原因是不管统一成ref类型还是value类型都有一定缺陷。

值类型value的话,在栈上分配空间,效率较高,但是它不支持多态,所以比如作为函数返回值使用时,有时会存在部分拷贝的问题。其实标准C++里面都是值类型value,别说有指针什么呢,指针本身不过是个整型的地址值,它还是值类型的,也别跟我说什么函数参数传递有传值和传址呢,即使传址,所传递的指针本身还是以值的形式传递的。
而引用类型ref,支持多态,但是它是在堆上分配空间,效率较低,而且会带来额外引用计数上的开销。

所以C++ /CX决定把两者区分开来,让开发者根据实际情况是选择。比如没必要支持多态的我们可以考虑使用value类型,比如希望交给系统管理引用计数的我们可以考虑使用ref类型。

2. public类

C++ /CX里有这样的定义:
  1. public ref class
  2. Object {};
  3. public value class
  4. Object {};
复制代码
用public来定义类,作用其实显而易见,所有准备对外公开的类必须设为public,比如组件里对外公布的类,如果不定义为public的话,外部是访问不到指定类型的。另外Native C++类(标准C++里的类)不能被定义为public,只有ref和value类型的类才可以设定为public,所以下面的代码编译会报错:
  1. public class
  2. Object {}; // compiler
  3. error
复制代码
另外还归纳出以下2点:
1. 标准C++方式的类不能被使用在public类的public属性成员中。
2. public ref类型类的public属性成员中,除非使用property,否则不能声明类成员变量。
3. public value类型的类的public属性成员中,不能声明类成员变量以外的成员,如函数等。

3. ^符号

C++ /CX中,就是用^来表示当前数据类型是ref引用类型。
比如有如下class:
  1. ref class SomeObj {
  2. public:
  3.      void SomeFunc();
  4. };
复制代码
那么在新建这个类对象时,由于是ref引用类型,所以会通过如下方式创建对象:
SomeObj^ obj = ref new SomeObj();
访问类具体成员对象时使用“->”
obj->SomeFunc();
^的变量代表它是引用类型的,系统会负责他们的引用计数,当引用计数为0时,它们会被销毁。

4. property

可以在public属性中用property关键字来公开类的成员变量,比如:
  1. ref class SomeObj {
  2. public:
  3.      property int propertyX;
  4. };
复制代码
可能你会觉得上面的写法跟不加property貌似没有什么区别,在使用确实上是一样的,但是用property的方式其实是会去自动生成针对m_propX的默认get(),set()函数,类似下面这样:
  1. ref class SomeObj {
  2. public:
  3.    property int propertyX{
  4.        int get() { return mX; }
  5.        void set(int x) { mX = x; };
  6.    }
  7. private:
  8.    int mX;
  9. };
复制代码
那property关键字的使用到底有什么实际意义呢?
首先,如果是public定义的类,那么它的public属性中只能通过property才能定义成员变量,如下这样的定义编译会出错:
  1. public ref class SomeObj
  2. {
  3. public:     int mX;
  4. // compiler error
  5. };
复制代码
其次,通过property可以控制成员变量的访问权限,比如只读,可读可写等,如下代码就把propertyX设置为只读了:
  1. ref class SomeObj
  2. {
  3. public:     property
  4. int propertyX
  5. {         
  6. int get()
  7. {
  8. return mX;
  9. }     
  10. }
  11. private:   int mX;
  12. };
复制代码
同时我们还可以自己定义成员变量的读操作或写操作,如下代码把写操作控制为只会被设置为非0的值:
  1. ref class SomeObj {
  2. public:
  3.      property int propertyX{
  4.         int get() { return mX; }
  5.         void set(int x) {
  6.             if (x != 0) mX = x;
  7.         };
  8.      }
  9. private:
  10.      int mX;
  11. };
复制代码
5. 委托delegate和事件event
先看delegate的一个实例:
  1. delegate void EventHandler(int x);
  2. ref class WinRTObj sealed
  3. {
  4. public:
  5.      WinRTObj() {
  6.           eHandler = ref new EventHandler([this](int x) {
  7.                this->mX = x;
  8.           });
  9.      }
  10.      void FireEvent(int x) {
  11.           eHandler(x);
  12.      }
  13.      EventHandler^ eHandler;
  14. private:
  15.      int mX;
  16. };
复制代码
delegate声明的EventHandler其实功能就类似于函数指针,在WinRTObj类中我们定义了EventHandler^类型的成员变量,并在构造函数中初始化,new EventHandler时的参数是一个Lambda表达式的匿名函数,所以在FireEvent中调用eHandler(x)时,其实就会去运行这个匿名函数。

我们再把event应用到上面这个例子中,看看event有什么功能:
  1. delegate void EventHandler(int x);
  2. ref class WinRTObj sealed
  3. {
  4. public:
  5.      WinRTObj() {
  6.           eHandler += ref new EventHandler([this](int x) {
  7.                this->mX = x;
  8.           });
  9.      }
  10.      void FireEvent(int x) {
  11.           eHandler(x);
  12.      }
  13.      event EventHandler^ eHandler;
  14. private:
  15.      int mX;
  16. };
复制代码
上面的代码我们只是在声明eHandler时用了event关键字,同时在构造函数创建eHandler时,把"="改成了"+="。那么event增加了什么特性呢?从"+="可以看出,我们可以通过"+="向eHandler添加多个委托,如下所示:
  1. WinRTObj() {
  2.      eHandler += ref new EventHandler([this](int x) {
  3.    this->mX = x;
  4.      });
  5.      eHandler += ref new EventHandler([this](int x) {
  6.    // ......
  7.      });
  8.      eHandler::add(ref new EventHandler([this](int x) {
  9.    // ......
  10.      }));
  11.      auto temp = eHandler::add(ref new EventHandler([this](int x) {
  12.      
  13.    // ......
  14.      }));
  15.      eHandler::remove(temp);
  16. }
复制代码
从上面的代码可以看出,除了用"+="来添加委托外,我们还可以用add方法,同时也可以用remove方法删除已经绑定的委托。
现在大家应该明白delegate结合event的具体作用了吧。
6. partial类
partial关键字也是用来修饰class,它可以让类可以再多个地方定义同一个类,在编译的时候会自动合并。比如:
  1. partial ref class N
  2. {
  3. public:
  4.    int Method1();
  5.    static int sData1;
  6. };
  7. ref class N
  8. {   
  9. public:
  10.      void Method2();
  11.      int mData2;
  12. };
复制代码
有什么用呢?其实在实际开发的代码中应该很少会用到,之所以需要partial,是因为Metro UI的界面是用XAML画的,VS会把XAML传变为实际代码,因为这些UI代码跟本身开发的UI逻辑代码等是属于同一个类,所以XAML转变的那部分会被定义为partial,然后编译的时候会被自动合并。




好了,关于C++ /CX的特性就说这么多,其实这些以外/CX还有很多新特性,比如内置类型,C++模板,枚举,异常等方面都有一些新的扩展。还是那句话,本文只是个说明的引子,更全的资料参照MSDN吧。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2024-11-27 12:41

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表