著作一覧 |
多重継承が可能だから、別にinterfaceはいらない。
下の例だと、Number(値が返せて、加算が可能)、Character(コードを返せる)は、単なるインターフェイスで、実装を継承するために用意したわけではない。
#include <stdio.h> class Number { public: virtual int value() = 0; virtual int add(int x) = 0; }; class Character { public: virtual int code() = 0; }; class A : public Character { public: int code() { return 0x41; } }; class HexA : public Number, public A { public: int value() { return 0x0a; } int add(int x) { return value() + x; } }; class One : public Number { public: int value() { return 1; } int add(int x) { return x + 1; } }; void printNumber(Number& n) { printf("number: value=%d\n", n.value()); printf("number: add(8)=%d\n", n.add(8)); } void printCharacter(Character& c) { printf("Character: code=0x%X\n", c.code()); } int main(int argc, char* argv[]) { A a; HexA ha; One one; printCharacter(a); printCharacter(ha); printNumber(ha); printNumber(one); return 0; }
実行するとこんなふうになる。
C:\Home\arton>cl test.cpp cl test.cpp Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86 Copyright (C) Microsoft Corp 1984-1998. All rights reserved. test.cpp Microsoft (R) Incremental Linker Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. /out:test.exe test.obj C:\Home\arton>test test Character: code=0x41 Character: code=0x41 number: value=10 number: add(8)=18 number: value=1 number: add(8)=9 C:\Home\arton>
この例では、HexAは、NumberインターフェイスとCharacterインターフェイスを両方実装している(かつ、Characterインターフェイスを実装したクラスAの実装を借用している)。
多重継承を正しく扱うためには、万能のObjectのような型を周到にデザインから排除しなければならない。そうでなければ、菱形継承の問題が顔を表すことになる。
また、多重継承をうまく利用するためにはデータを排除することが重要なのではないか?と語るスコットEffective C++マイヤー。
それでは、実体を伴わないメソッドの集合の定義としてinterface(起源はOMG IDLなのかな?)を採用したJavaには菱形(ダイアモンド)継承問題はないのか? というとダイアモンドは永遠にということも。
ダイアモンドは永遠にを読んでいて??となったが、Javaってそうなのか。C#だと全然OKなんだけど。
public interface HonestClass { bool turnInLostMoney(); } public interface DishonestClass { bool turnInLostMoney(); } public class Citizen : HonestClass, DishonestClass { bool HonestClass.turnInLostMoney() { return true; } bool DishonestClass.turnInLostMoney() { return false; } public static void Main() { Citizen c = new Citizen(); System.Console.WriteLine("Do you turn in lost money ?"); System.Console.WriteLine(((HonestClass)c).turnInLostMoney()); System.Console.WriteLine(((DishonestClass)c).turnInLostMoney()); } }
実行すると
C:\Home\arton>csc Citizen.cs csc Citizen.cs Microsoft(R) Visual C# .NET Compiler version 7.10.3052.4 for Microsoft(R) .NET Framework version 1.1.4322 Copyright (C) Microsoft Corporation 2001-2002. All rights reserved. C:\Home\arton>citizen citizen Do you turn in lost money ? True False C:\Home\arton>
変なところで不便な善良な市民には住みにくい仕様だな。
「とんでもない欠陥が見つかりました。至急リコールを」
「いらんいらん。実害は無いから」
「な、何を根拠に?」
「だってリコールしたらブランドイメージにキズがつくっていう実害があるでしょ? それに対してリコールしなければ当然その実害は無い。実害が無いんだからこのままで良い。シュアロジカリー」
「そりゃ無理です。至急リコールを」
「無理だと思ったら何も始まらない。我が社のチャレンジが日本を変える。やらなきゃ!」
「そりゃ人死にが出たら変わるでしょうが、それでは手遅れってものです。リコール無しで済ますのは無理です」
「『無理だ』は我が社の禁句にせえへんか?」
「我が社が禁句にしたところで、実害に合うのは我が社以外の人なんですよ」
「まぁまぁ、知らぬが仏と言うではないか」
「そりゃ確かに知らないうちに仏になっちゃうでしょうけど、生き残った人にはバレバレですよ」
「そっか生き残りが出ると言うことは、シェアが低いのが問題ということだな。目指せナンバーワン!」
「無理ですよ」
「無理だと思ったら何も始まらない。我が社のチャレンジが日本を変える。やらなきゃ!」
「この会社で仕事を続けるのは無理だな……」
ジェズイットを見習え |