課題で取り組んでもらっている、動物の進化を表すクラスの概要を示す。
Animal( const char s[] ) {
const char* get_name() const { return name ; }
virtual void move() = 0 ;
virtual void birth() = 0 ;
class Bird : public Animal {
Bird( const char s[] ) : Animal( s ) {}
printf( "%s fry.\n" , get_name() ) ;
printf( "%s lay egg.\n" , get_name() ) ;
class Mammal : public Animal {
Mammal( const char s[] ) : Animal( s ) {}
printf( "%s walk.\n" , get_name() ) ;
printf( "%s lay baby.\n" , get_name() ) ;
// 動物クラス
class Animal {
private:
char name[ 10 ] ;
public:
Animal( const char s[] ) {
strcpy( name , s ) ;
}
const char* get_name() const { return name ; }
virtual void move() = 0 ;
virtual void birth() = 0 ;
} ;
// 鳥類クラス
class Bird : public Animal {
public:
Bird( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s fry.\n" , get_name() ) ;
}
virtual void birth() {
printf( "%s lay egg.\n" , get_name() ) ;
}
} ;
// 哺乳類クラス
class Mammal : public Animal {
public:
Mammal( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s walk.\n" , get_name() ) ;
}
virtual void birth() {
printf( "%s lay baby.\n" , get_name() ) ;
}
} ;
int main() {
Bird chiken( "piyo" ) ;
chiken.move() ;
chiken.birth() ;
Mammal cat( "tama" ) ;
cat.move() ;
cat.birth() ;
return 0 ;
}
// 動物クラス
class Animal {
private:
char name[ 10 ] ;
public:
Animal( const char s[] ) {
strcpy( name , s ) ;
}
const char* get_name() const { return name ; }
virtual void move() = 0 ;
virtual void birth() = 0 ;
} ;
// 鳥類クラス
class Bird : public Animal {
public:
Bird( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s fry.\n" , get_name() ) ;
}
virtual void birth() {
printf( "%s lay egg.\n" , get_name() ) ;
}
} ;
// 哺乳類クラス
class Mammal : public Animal {
public:
Mammal( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s walk.\n" , get_name() ) ;
}
virtual void birth() {
printf( "%s lay baby.\n" , get_name() ) ;
}
} ;
int main() {
Bird chiken( "piyo" ) ;
chiken.move() ;
chiken.birth() ;
Mammal cat( "tama" ) ;
cat.move() ;
cat.birth() ;
return 0 ;
}
ここで、カモノハシを作るのであれば、どうすれば良いだろうか?
class SeaBream : public Animal {
Mammal( const char s[] ) : Animal( s ) {}
printf( "%s walk.\n" , get_name() ) ;
printf( "%s lay egg.\n" , get_name() ) ;
class SeaBream : public Animal {
public:
Mammal( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s walk.\n" , get_name() ) ;
}
virtual void birth() {
printf( "%s lay egg.\n" , get_name() ) ;
}
} ;
class SeaBream : public Animal {
public:
Mammal( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s walk.\n" , get_name() ) ;
}
virtual void birth() {
printf( "%s lay egg.\n" , get_name() ) ;
}
} ;
この例では、簡単な処理だが、move() の中身が複雑であれば、改めて move() を宣言するのではなく、継承するだけの書き方ができないだろうか?
C++ には、複数のクラスから、派生する多重継承という機能がある。であれば、鳥類と哺乳類から進化したのだから、以下のように書きたい。
class SeaBream : public Bird , Mammal {
class SeaBream : public Bird , Mammal {
} ;
class SeaBream : public Bird , Mammal {
} ;
しかし、カモノハシに move() を呼び出すと、鳥類の move() と哺乳類の move() のどちらを動かすか曖昧になる。また、派生クラスは親クラスのデータ領域と、派生クラスのデータ領域を持つため、鳥類の name[] と、哺乳類の name[] を二つ持つことになる。
Animal( const char s[] ) {
const char* get_name() const { return name ; }
virtual void move() = 0 ;
const char* move_method() { return "fly" ; }
const char* move_method() { return "walk" ; }
class Bird : public Animal , Wind {
Bird( const char s[] ) : Animal( s ) {}
printf( "%s %s.\n" , get_name() , move_method() ) ;
class Mammal : public Animal , Leg {
Mammal( const char s[] ) : Animal( s ) {}
printf( "%s %s.\n" , get_name() , move_method() ) ;
class Animal {
private:
char name[ 10 ] ;
public:
Animal( const char s[] ) {
strcpy( name , s ) ;
}
const char* get_name() const { return name ; }
virtual void move() = 0 ;
} ;
// 羽
class Wing {
public:
const char* move_method() { return "fly" ; }
} ;
//
class Leg {
public:
const char* move_method() { return "walk" ; }
} ;
class Bird : public Animal , Wind {
public:
Bird( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s %s.\n" , get_name() , move_method() ) ;
}
} ;
class Mammal : public Animal , Leg {
public:
Mammal( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s %s.\n" , get_name() , move_method() ) ;
}
} ;
class Animal {
private:
char name[ 10 ] ;
public:
Animal( const char s[] ) {
strcpy( name , s ) ;
}
const char* get_name() const { return name ; }
virtual void move() = 0 ;
} ;
// 羽
class Wing {
public:
const char* move_method() { return "fly" ; }
} ;
//
class Leg {
public:
const char* move_method() { return "walk" ; }
} ;
class Bird : public Animal , Wind {
public:
Bird( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s %s.\n" , get_name() , move_method() ) ;
}
} ;
class Mammal : public Animal , Leg {
public:
Mammal( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s %s.\n" , get_name() , move_method() ) ;
}
} ;
# うーむ、継承する処理が1行程度でかける処理だと、どのやり方も「継承が便利」というように見えないな…(x_x;
Animal( const char s[] ) {
const char* get_name() const { return name ; }
virtual void move() = 0 ;
virtual void birth() = 0 ;
class Bird : public virtual Animal {
Bird( const char s[] ) : Animal( s ) {}
printf( "%s fry.\n" , get_name() ) ;
printf( "%s lay egg.\n" , get_name() ) ;
class Mammal : public virtual Animal {
Mammal( const char s[] ) : Animal( s ) {}
printf( "%s walk.\n" , get_name() ) ;
printf( "%s lay baby.\n" , get_name() ) ;
class SeaBream : public virtual Bird , virtual Mammal {
SeaBream( const char s[] ) : Animal( s ) {}
class Animal {
private:
char name[ 10 ] ;
public:
Animal( const char s[] ) {
strcpy( name , s ) ;
}
const char* get_name() const { return name ; }
virtual void move() = 0 ;
virtual void birth() = 0 ;
} ;
// 鳥類クラス
class Bird : public virtual Animal {
public:
Bird( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s fry.\n" , get_name() ) ;
}
virtual void birth() {
printf( "%s lay egg.\n" , get_name() ) ;
}
} ;
// 哺乳類クラス
class Mammal : public virtual Animal {
public:
Mammal( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s walk.\n" , get_name() ) ;
}
virtual void birth() {
printf( "%s lay baby.\n" , get_name() ) ;
}
} ;
class SeaBream : public virtual Bird , virtual Mammal {
public:
SeaBream( const char s[] ) : Animal( s ) {}
void move() {
Mammal::move() ;
}
void birth() {
Bird::birth() ;
}
} ;
class Animal {
private:
char name[ 10 ] ;
public:
Animal( const char s[] ) {
strcpy( name , s ) ;
}
const char* get_name() const { return name ; }
virtual void move() = 0 ;
virtual void birth() = 0 ;
} ;
// 鳥類クラス
class Bird : public virtual Animal {
public:
Bird( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s fry.\n" , get_name() ) ;
}
virtual void birth() {
printf( "%s lay egg.\n" , get_name() ) ;
}
} ;
// 哺乳類クラス
class Mammal : public virtual Animal {
public:
Mammal( const char s[] ) : Animal( s ) {}
virtual void move() {
printf( "%s walk.\n" , get_name() ) ;
}
virtual void birth() {
printf( "%s lay baby.\n" , get_name() ) ;
}
} ;
class SeaBream : public virtual Bird , virtual Mammal {
public:
SeaBream( const char s[] ) : Animal( s ) {}
void move() {
Mammal::move() ;
}
void birth() {
Bird::birth() ;
}
} ;
ただし、多重継承は親クラスの情報と、メソッドを継承する。この場合、通常だと name[] を二つ持つことになるので、問題が発生する。そこで、親クラスの継承に virtual を指定することで、ダイヤモンド型継承の 2つの属性をうまく処理してくれるようになる。
しかし、多重継承は処理の曖昧さや効率の悪さもあることから、採用されていないオブジェクト指向言語も多い。特に Java は、多重継承を使えない。その代わりに interface という機能が使えるようになっている。