文字列で出力
問題
次は、インスタンスを文字列として表現して出力する場合です。この中でも1つだけ出力結果が違うものがあります。それは、どの言語でしょうか?
program Project1; {$APPTYPE CONSOLE} type TMyClass = record class operator Explicit(x: TMyClass): string; end; class operator TMyClass.Explicit(x: TMyClass): string; begin Result := ’TMyClass’; end; var obj: TMyClass; begin Writeln(string(obj)); end.
#include <iostream> using namespace std; class TMyClass { friend ostream& operator <<(ostream& os, const TMyClass& obj) { os << "TMyClass"; return os; } }; int main(int argc, char* argv[]) { cout << TMyClass() << endl; return 0; }
package project1; class TMyClass { public String toString() { return "TMyClass"; } } public class Project1 { public static void main(String[] args) { System.out.println(new TMyClass()); } }
namespace project1 { class TMyClass { public string toString() { return "TMyClass"; } } public class Project1 { public static void Main() { System.Console.WriteLine(new TMyClass()); } } }
<?php class TMyClass { public function __toString() { return "TMyClass"; } } echo (string)new TMyClass() . "\n"; ?>
class TMyClass def to_s "TMyClass" end end puts TMyClass.new
解説
正解は「C#」。
C#では、期待した「TMyClass」ではなく「project1.TMyClass」が出力されます。それ以外の言語では正しく「TMyClass」が出力されます。これは一体どうしたというのでしょう。
Delphi(record型のみ)では明示的なキャストが可能ですし、C++では演算子オーバーロードを定義することが可能です。JavaではtoString()メソッドを、PHPでは__toString()メソッドを、Rubyではto_sメソッドをオーバーライドすることにより、文字列としての表現方法を独自に実装することが可能です。もちろんC#でも「ObjectクラスのToString()メソッド」をオーバーライドすることで同様の処理が可能です。
しかし問題のコードでは、オーバーライドが正しく行われていません。コンパイル時には警告もエラーも発生しませんでした。C#ではメソッドの大文字・小文字を区別しますし、メソッドのオーバーライドにはoverride修飾子が必要なのです。
このため「ObjectクラスのToString()メソッド」が呼び出され、その既定の実装である「クラスの完全限定名」が文字列として返されたのです。正しくは以下のように記述します。
class TMyClass { public override string ToString() { return "TMyClass"; } }