さて、前回の授業で何となくオブジェクト指向の概念は分かってもらえたと思います。
今回は、オブジェクトに柔軟性と拡張性を与えるための機能である「継承」を学びます。
クラスの継承とは
継承は、簡単に言ってしまえば「遺伝」です。
親から子が産まれる時に親のDNAを引き継ぎますが、完全に親のコピーなわけではありません。新たな能力の獲得がある場合もありますし、育つ環境によって個性が出てきます。
このように、クラスが型だとすると、その型の属性を引き継ぎなおかつ新しい属性を付加したクラスを作成することを「継承」と呼ぶのです。
クラスの継承
さて、ここからが本番のクラスの継承です。Circleクラスはそのまま使いますが、このクラスを継承して色彩の機能を持たせたColorCircleクラスを作成します。最終的には別々の色彩を持った円を作成します。

Circleクラスを作成した時と同じようにColorCircleクラスファイルを作成してください。以下のようなファイルの構成になります。

これらのファイルに書き込んでいきます。
ColorCircle.hpp
#ifndef ColorCircle_hpp
#define ColorCircle_hpp
#include
#include "ofMain.h"
#include "Circle.hpp"
class ColorCircle: public Circle {
public:
void init(float _y, int _eSize, float _speed, ofColor _eColor); //初期化メソッド
void update(); //更新
void displayColor(); //描画
ofColor eColor; //色彩の変数であるeColorを宣言
private:
};
#endif
ColorCircle.cpp
#include "ColorCircle.hpp"
void ColorCircle::init (float _y, int _eSize, float _speed, ofColor _eColor) { //初期化用のメソッド
Circle::init(_y, _eSize, _speed); //親クラス(Circleクラス)のコンストラクタを実行する
eColor = _eColor;
}
void ColorCircle::update() {
Circle::update(); //親クラス(Circleクラス)のupdate()メソッドを実行
}
void ColorCircle::displayColor() {
ofSetColor(eColor); //色彩を設定
Circle::display(); //親クラス(Circleクラス)のdisplay()メソッドを実行
}
このクラスを宣言することによって、円に色を定義することが可能になりました。
この場合のCircleクラスを親クラス(スーパークラス)、ColorCircleクラスを子クラス(サブクラス)と呼びます。親子の関係となっているということですね。
そして、最終的にcolorCircleSampleファイルでColorCircleクラスのインスタンスを使います。
ofApp.h
#pragma once
#include "ofMain.h"
#include "ColorCircle.hpp"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
ColorCircle c1, c2; //ColorCircleクラスのオブジェクト(インスタンス)を宣言
};
ofApp.cpp
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
ofBackground(255, 255, 255);
ofSetCircleResolution(64);
c1.init(100, 10, 1.0, ofColor(255, 0, 0)); //オブジェクトを作成
c2.init(300, 40, 3.5, ofColor(0, 0, 255));
}
//--------------------------------------------------------------
void ofApp::update(){
//c1オブジェクトのクラスであるColorCircleクラスのupdate(), display()メソッドを実行
c1.update();
c2.update();
}
//--------------------------------------------------------------
void ofApp::draw(){
c1.displayColor();
c2.displayColor();
}
クラスをカスタマイズ
上記のサンプルを元に、キーボードの矢印キーでオブジェクトのスピードが変わるように書き換えてみましょう。まずは、Circleクラスにスピードを設定するメソッド(setSpeed)を追加します。

Circle.hpp
#ifndef Circle_hpp
#define Circle_hpp
#include
#include "ofMain.h"
class Circle {
public:
void init(float _y, int _eSize, float _speed); //初期化メソッド
void update(); //更新
void display(); //描画
void setSpeed(float _speed); //スピードを設定
float xPos, yPos, eSize, speed;
private:
};
#endif
Circle.cpp
#include "Circle.hpp"
void Circle::init (float _y, int _eSize, float _speed) {
xPos = 0.0; //x座標の初期値は0.0
yPos = _y; //y座標の初期値はオブジェクトを宣言した際の引数になる
eSize = _eSize;
speed = _speed; //speedの初期値もオブジェクト宣言の際の引数
}
//円の位置を更新するメソッド
void Circle::update() {
xPos += speed; //speed分のx座標を移動
if (xPos > ofGetWidth()) { //円のx座標がウィンドウの幅を超えたら、
xPos = 0; //位置を0に戻す
}
}
void Circle::display(){
ofDrawCircle(xPos, yPos, eSize); //円を描く
}
//スピードを設定するメソッド
void Circle::setSpeed(float _speed){
speed += _speed;
if(speed < 0.0) speed = 0.0; //0未満にはならないようにする
}
そして、ColorCircleクラスに、スピードを変えるfaster(), slower()メソッドを追加します。
ColorCircle.hpp
#ifndef ColorCircle_hpp
#define ColorCircle_hpp
#include
#include "ofMain.h"
#include "Circle.hpp"
class ColorCircle: public Circle {
public:
void init(float _y, int _eSize, float _speed, ofColor _eColor); //初期化メソッド
void update(); //更新
void displayColor(); //描画
void faster(); //スピードを速くする
void slower(); //スピードを遅くする
ofColor eColor; //色彩の変数であるeColorを宣言
private:
};
#endif
ColorCircle.cpp
#include "ColorCircle.hpp"
void ColorCircle::init (float _y, int _eSize, float _speed, ofColor _eColor) { //初期化用のメソッド
Circle::init(_y, _eSize, _speed); //親クラス(Circleクラス)のコンストラクタを実行する
eColor = _eColor;
}
void ColorCircle::update() {
Circle::update(); //親クラス(Circleクラス)のupdate()メソッドを実行
}
void ColorCircle::displayColor() {
ofSetColor(eColor); //色彩を設定
Circle::display(); //親クラス(Circleクラス)のdisplay()メソッドを実行
}
//スピードを速くするメソッド
void ColorCircle::faster() {
Circle::setSpeed(0.5); //親クラス(Circleクラス)のsetSpeed()に0.5を渡す
}
//スピードを遅くするメソッド
void ColorCircle::slower() {
Circle::setSpeed(-0.5); //親クラス(Circleクラス)のsetSpeed()に-0.5を渡す
}
最後に、ofApp.hとofApp.cppには、keyPressed()の機能を追加します。
ofApp.h
#pragma once
#include "ofMain.h"
#include "ColorCircle.hpp"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
ColorCircle c1, c2; //ColorCircleクラスのオブジェクト(インスタンス)を宣言
};
ofApp.cpp
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
ofBackground(255, 255, 255);
ofSetCircleResolution(64);
c1.init(100, 10, 1.0, ofColor(255, 0, 0)); //オブジェクトを作成
c2.init(300, 40, 3.5, ofColor(0, 0, 255));
}
//--------------------------------------------------------------
void ofApp::update(){
//c1オブジェクトのクラスであるColorCircleクラスのupdate(), display()メソッドを実行
c1.update();
c2.update();
}
//--------------------------------------------------------------
void ofApp::draw(){
c1.displayColor();
c2.displayColor();
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){
if(key == OF_KEY_UP){ //上に動く
c1.faster();
c2.faster();
} else if (key == OF_KEY_DOWN) { //下に動く
c1.slower();
c2.slower();
}
}
おまけ
もちろん、上記のサンプルを配列化することもできます。このことによって、たくさんの自律的なオブジェクトを生成することができます。興味がある人はダウンロードして動かしてみましょう。
