| 著作一覧 |
多重継承が可能だから、別に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>
変なところで不便な善良な市民には住みにくい仕様だな。
「とんでもない欠陥が見つかりました。至急リコールを」
「いらんいらん。実害は無いから」
「な、何を根拠に?」
「だってリコールしたらブランドイメージにキズがつくっていう実害があるでしょ? それに対してリコールしなければ当然その実害は無い。実害が無いんだからこのままで良い。シュアロジカリー」
「そりゃ無理です。至急リコールを」
「無理だと思ったら何も始まらない。我が社のチャレンジが日本を変える。やらなきゃ!」
「そりゃ人死にが出たら変わるでしょうが、それでは手遅れってものです。リコール無しで済ますのは無理です」
「『無理だ』は我が社の禁句にせえへんか?」
「我が社が禁句にしたところで、実害に合うのは我が社以外の人なんですよ」
「まぁまぁ、知らぬが仏と言うではないか」
「そりゃ確かに知らないうちに仏になっちゃうでしょうけど、生き残った人にはバレバレですよ」
「そっか生き残りが出ると言うことは、シェアが低いのが問題ということだな。目指せナンバーワン!」
「無理ですよ」
「無理だと思ったら何も始まらない。我が社のチャレンジが日本を変える。やらなきゃ!」
「この会社で仕事を続けるのは無理だな……」
ジェズイットを見習え |