今まで説明してきたのは、ボタンを押したとかそのような反応にたいして、シグナルをハンドリングすることで何かアクションを起こすようなやり方でした。これは物事をなしとげる大変うまいやり方のひとつですが、やり方は唯ひとつではありません。
シグナルハンドラをシグナルにつないでいくという面倒な作業を行うかわりに、単純にウィジット(例えばButton)を継承した新しいクラスを作り、そのデフォルトのシグナルハンドラ(例えばButton::on_clicked())をオーバーライドする方法が使えます。こうすればシグナルハンドラ全てにフックするよりも、もっとずっとシンプルになるでしょう。
サブクラス化がいつも物事をなしとげるベストの方法ではあるとは限りません。これが有用なのはウィジット自分自身のシグナルは自分でハンドルしてもらいたい場合です。シグナルをハンドルするのに別のクラスが必要な場合は別のハンドラに接続する必要があるでしょう。こうした方がいいのは他にも、多数のオブジェクトにひとつのシグナルをハンドルさせる場合や、ひとつのシグナルハンドラに多数のオブジェクトが発行するひとつのシグナルを処理させる場合です。
gtkmmのクラスはオーバーライドを念頭において設計されていますから、動作を上書きできる仮想メンバ関数を持っています。
さて、それではオーバーライドの例をみましょう:
#include <gtkmm/button.h>
class OverriddenButton : public Gtk::Button
{
protected:
virtual void on_clicked();
}
void OverriddenButton::on_clicked()
{
std::cout << "Hello World" << std::endl;
// call the base class's version of the method:
Gtk::Button::on_clicked();
}
ここでは新しいクラスOverriddenButtonを定義しています。これはGtk::Buttonを継承しています。コードで唯一変更しているのはon_clicked()メソッドです。このメソッドはGtk::Buttonがclickedシグナルを発行したときに常に呼び出されます。メソッドはstdoutに"Hello World"と出力し、それからオリジナルのオーバーライドされたメソッドを呼び出して、Gtk::Buttonにオーバーライドされていない場合にすべきであったことをさせています。
常に親のメソッドを呼ぶ必要はありません。そのようにする場面は何度もあるでしょう。覚えておいてください。コードでは親のメソッドを"Hello World"と出力した後で呼び出していますが、本来はそうする前に親のメソッドを呼び出すべきです。このような単純な例では問題となりませんが、そうしないと良くないことが起きる場合があります。シグナルを使う場合、このように細部を変更することはそれほど簡単ではありませんし、接続するシグナルハンドラで処理できないことをここに書くのですから、親のメソッドはカスタムコードの中間で呼び出すこともできます。