Integerクラスのサブクラス LoggableIntegerクラスには、スーパクラスの getValue関数をオーバライドする。この関数は Integerのそれど同様 int型の値を返すが、この関数を呼び出した回数を変数 counterに記録し、getAccessCount関数で読み出せるようにする。
ヘッダファイル (header file)
LoggableInteger.hはつぎの通り。/* 13.Aug.2012 kei */ #ifndef _Included_LoggableInteger #define _Included_LoggableInteger typedef struct LoggableInteger* LoggableInteger; typedef struct interface_LoggableInteger { void (*finalize)(LoggableInteger this); int (*getValue)(LoggableInteger this); int (*getAccessCount)(LoggableInteger this); }* interface_LoggableInteger; extern void static_LoggableInteger(interface_LoggableInteger interface_methods); extern LoggableInteger new_LoggableInteger(int value); extern void LoggableInteger_init(LoggableInteger this, int value); extern void LoggableInteger_finalize(LoggableInteger this); extern int LoggableInteger_getValue(LoggableInteger this); extern int LoggableInteger_getAccessCount(LoggableInteger this); #endif /* _Included_LoggableInteger */
変数や関数が違う点以外は IntegerValueクラスのヘッダと同様。
ソースファイル (source file)
LoggableInteger.cはつぎの通り。/* 13.Aug.2012 kei */ #include <LoggableInteger.h> #include <Integer.h> /**************************************************************** private ****************************************************************/ #include <malloc.h> struct LoggableInteger { interface_LoggableInteger interface_methods; /* Integer class */ int value; /* LoggaableInteger class */ int counter; }; static struct interface_LoggableInteger interface_methods; static struct interface_Integer super; static int getValue(LoggableInteger this) { ++this->counter; return Integer_getValue((Integer)this); } static int getAccessCount(LoggableInteger this) { return this->counter; } /**************************************************************** public ****************************************************************/ void static_LoggableInteger(interface_LoggableInteger interface_methods) { /* ToDo: lock interface_methods */ if (interface_methods->finalize == NULL) { static_Integer(&super); static_Integer((interface_Integer)interface_methods); interface_methods->getValue = getValue; interface_methods->getAccessCount = getAccessCount; } } LoggableInteger new_LoggableInteger(int value) { static_LoggableInteger(&interface_methods); LoggableInteger this = (LoggableInteger)malloc(sizeof(struct LoggableInteger)); if (this != NULL) LoggableInteger_init(this, value); return this; } void LoggableInteger_init(LoggableInteger this, int value) { Integer_init((Integer)this, value); this->interface_methods = &interface_methods; } void LoggableInteger_finalize(LoggableInteger this) { this->interface_methods->finalize(this); } int LoggableInteger_getValue(LoggableInteger this) { return this->interface_methods->getValue(this); } int LoggableInteger_getAccessCount(LoggableInteger this) { return this->interface_methods->getAccessCount(this); }
これも IntegerVariableクラスとほぼ同じだが、getValue関数をオーバライドするため、LoggableIntegerクラスで改めて定義し、static_LoggableIntegerで getValue関数を設定している。
static_Integer関数を呼び出した時点で、interface_methodsには一旦スーパクラスの getValue関数が設定される。その後でサブクラスの関数を上書きしている。 概念だけでなく実際に上書きしているので、如何にも "override"の感じがする。
関数テーブルは interface_methodsのほかに Integerクラス用の superも定義している。
これは、Integerクラスの getValueを呼び出すために必要となる。
getValue関数の中では、 super.getValue((Integer)this); を呼び出すことにより、スーパクラスの取得関数を利用している。
動作確認 (unit test)
テストケース LoggableIntegerTest.cはつぎの通り。/* 14.Aug.2012 kei */ #define import_lwd_unit_Assert #define import_lwd_unit_CUnit #include <lwd/unit/Assert.h> #include <lwd/unit/CUnit.h> #include <LoggableInteger.h> /**************************************************************** test cases ****************************************************************/ static LoggableInteger instance; void setUp() { instance = new_LoggableInteger(813); } void tearDown() { LoggableInteger_finalize(instance); } void testNewAndFinalize() { /* setUp, tearDown */ } void testGetValue() { int value = LoggableInteger_getValue(instance); Assert_equalsInt("A value must be 813.", 813, value); } void testGetAccessCount() { Assert_equalsInt("must be zero.", 0, LoggableInteger_getAccessCount(instance)); LoggableInteger_getValue(instance); Assert_equalsInt("must be 1.", 1, LoggableInteger_getAccessCount(instance)); } /**************************************************************** main ****************************************************************/ int main(int argc, char** argv) { return CUnit_test(argc, argv); }
テストのビルドと実行結果も残しておく。
$ make cc -g -finstrument-functions -I. -I /export/home/kei/c/core/include -I /export/home/ kei/c/experimental/include -I /export/home/kei/c/io/include -I /export/home/kei/c/lang /include -I /export/home/kei/c/message/include -I /export/home/kei/c/unit/include -I /export/home/kei/c/util/include -I /export/home/kei/c/x11/include -I ../../char/ include -I ../../class1/include -c -o LoggableIntegerTest.o LoggableIntegerTest.c $ ./LoggableIntegerTest [CUnit] ./LoggableIntegerTest: testGetAccessCount [CUnit] ./LoggableIntegerTest: testGetValue [CUnit] ./LoggableIntegerTest: testNewAndFinalize [SUCCEED] testGetAccessCount in 1(ms) [SUCCEED] testGetValue in 2(ms) [SUCCEED] testNewAndFinalize in 2(ms) successes: 3 (100.0%) failures: 0 (0.0%) errors: 0 (0.0%) total: 3 in 5(ms) $
竜巻情報が出された。豹が降る恐れがあるとか言っている。
0 件のコメント:
コメントを投稿