副産物というわけではないが、MayaSDKに関する自分なりの感想を書いてみた。
このドキュメントの対象読者はある程度C++の知識があることを前提にしています。ダウンキャストやRTTIなど基礎的でない要素についてはある程度解説を加えてありますが、最低、仮想関数と多態がなんであるかは知っていなければC++の基本を知ってから読んでください。
このドキュメントは2001/2/13時点でMaya3.0のSDKを使った感想です。今年度で学校を卒業したらMayaを使う権利もなくなりますから、改定することもありません。
A. MayaSDKがC++の型保証を使わず、RTTIを独自に実装しているからです。
MayaSDKではすべてがMObjectであるため、(void*のようなもの)
MObject obj = dagFn.child(); if ( obj.hasFn( MFn::kCamera ) ) { MFnCamera cam( obj );
のようにして、オブジェクトとMFnのプレフィクスから始まる関数セットが適用できるか確認しなければ危険です。
また、サンプルコードでは
switch (type) { case MFn::kCamera: カメラ用処理A break; case MFn::kLight: ライト用処理B break;
というコードが散見されます。こういった処理は仮想関数と多態で実現するとシンプルに書けますが、すべてがMObjectであるMayaSDKでは選択の余地がありません、慣れるしかないでしょう。
はっきり言って、上のswitch文は初心者のコードにしか思えません。できる限り仮想関数で対応し、最悪
Camera* c = dynamic_cast(pointer); // 失敗ならcには0が入る。 if(c){ カメラとその派生クラスの処理 }
とすべきでしょう。上記のswitch文は標準C++で書けばtypeidを使った
if(typeid(Camera) == typeid(*pointer)){ カメラの処理 }
という文に相当しますが、これではCameraの派生クラスを作るたびに分岐をひとつ増やすことになります。(Mayaは派生で拡張しないから別にいい?)
# MayaSDKではエラー処理と型識別の両方でチェックが必要なため、ソースコードの分岐はかなりキツイです。
A. 設計者がC++のパワーとSmalltalkのような柔軟さの両方を欲したか、純粋オブジェクト指向主義者なのでしょう。
一般に、型のない言語では、実行時に型を識別したり、メソッドがあるかどうか判別したりする機能が強力にサポートされています。つまり、普段は型を意識しないが、必要ならば意識することができるのです。(それでも実行時であるため、CやPascalのようにコンパイル時にエラーを検出することはできません)MayaSDKもそれにならって、RTTIを独自に実装し実行時の型識別をサポートし、MFn〜という操作系のクラス群とMObjectクラスを分離して型無しの言語を目指したということでしょう。
C++という言語では今でこそRTTIが言語でサポートされていますが、MayaSDK設計当時は無かった筈です。実行時にいろいろ便利なサポートがあるからこそ、型を意識しなくとも済むのですが、C++でそれをやるということは、ガードレールのない道路をアクセル全開で突っ走るようなものと言えます。(そしてMayaSDKはガードレールも自分で作ってしまった。)
Q1の感想でも書いた通り、MayaSDKのRTTIは不完全です。派生クラスを上手く扱えませんから、プロキシクラスってものを噛ませないとデータ型ひとつ増やせません。C++にはC++の書き方ってものがあるわけで、Smalltalk(と思うよ)の書き方を持ち込むとこうなるっていう見本ですね。
A. それが仕様です。
としか、言いようがありません。型なしを選んだ代償(実行時の明示的な型チェックが必要)も相まってMayaSDKライブラリを使ったソースコードは相当に見難いです。エラーを捕らえたら、そこから例外を飛ばすしかないでしょう。(なぜ、例外を使わないのかは私には理解不能です。)
また、MayaSDKでは自前のRTTIを使ってMObjectがなんであるかを判断しますが、その判別はあくまでライブラリを使うユーザーに委ねられるため、MObjectに間違った関数セットを適用してしまうことが簡単に起きてしまいます。つまり、関数が失敗することは例外でもなんでもなく、かなり高い確率で起こります。面倒くさいからと省いたりすると痛い目見ます。(経験談です^^;)
ほとんどの関数は戻値がMStatusクラスであるか、MStatusのポインタを引数に取るかして、エラー処理を行います。具体的には
MStatus status = object.Function(); if(MS::kSuccess != status){ エラー処理 } object.Function2(&status); if(MS::kSuccess != status){ エラー処理 }
という感じの記述になるため、(型識別の条件分岐もあるため)ソースコードはかなり見難いです。また、MStatusの返る経路も、戻り値か引数かはドキュメントを見ないとわからないため、コーディング作業はリファレンスが開ける環境でなければ難しいでしょう。
これはMayaSDKをそっくり包んでしまうラッパーライブラリを製作するか、A|Wがライブラリを改定しない限りどうしようもありません。(つまり、我々にはどうしようもないってことです^^;)慣れましょう。
例外クラスの実装例 :
#ifndef ATS_MEXCEPTION_H #define ATS_MEXCEPTION_H #include#include namespace ats { class MException : public std::exception { private: std::string m_msg; MStatus m_state; public: MException(const char* msg, const MStatus& state) throw() : m_msg(msg), m_state(state) {} MException(const std::string& msg, const MStatus& state) throw() : m_msg(msg), m_state(state) {} virtual ~MException() throw() {} virtual const char *what() const throw() { return m_msg.c_str(); } virtual MStatus status() const throw() { return m_state; } }; } #endif
A. ※ありません^^;、(検索エンジンにかけてみればわかります。)
※ 3.0ではということ
私が確認した限りでは、Ken Taki's Maya Page on Line!のMaya API(SDK) White Paperに10ページ程基礎的な解説があります。Digital Matrixにコマンドラインでのビルドの方法と少々の解説があります。A.M.BitにはこのFAQがあります。
A. 慣れましょう。サンプルコードの改造を繰り返し、頭をMayaSDK漬けにする以外方法はありません。^^;
MayaSDKだけが特殊なわけではなく、C++のメジャーなライブラリはどれも特殊で、教科書のお手本通りに書かれたものは一つもありません。それでもMayaSDKに違和感を覚えるのはC++で型のない性質をやってしまったからでしょう。一度、型の無い言語で型無しのお手軽さを味わってみなければ理解できないかもしれません。
# とりあえず型無しをためすだけなら、ブラウザに付いているECMAScript(JavaScript)が良いでしょう。本格的にオブジェクト指向からやりたいならRubyがお勧めです。遠回りですが最高の方法は、デザインパターンを習得し、それを踏まえてSmalltalkに触れることです。
A. VisualStudioにDLLをデバッグする機能があります。
Mayaには-dオプションによるデバッグのための機能がありますが、Windows版にはないようです。(3.0にて)VisualC++(6.0)でDLL(MLL)をデバッグするには。
1. C++ではあくまで基底クラスのポインタをキャストすることを指す。実態をアップキャストしたあと元に戻すことは不可能である。アップキャストした段階でスライシングが起こっている。
2. 極端すぎるかもしれないが、間違いとも思わない。
3. RTTIは安全なダウンキャスト(基底クラスから派生クラスにキャストすること)や実行時に型を識別するために必要ですが、MayaSDKも他の大規模ライブラリの例に漏れず独自のRTTIを実装しています。C++では最近(1998)までRTTI(Run Time Type Information : 実行時型情報)をサポートしていませんでした。