読者です 読者をやめる 読者になる 読者になる

継承とかしてみる

Program Bin

面白いかと思ったけどツマらなかった。そもそもスクリプト言語コンパイル言語のクラスを継承してそれをまたコンパイル言語側で使いたいこととかあるはずない。そしてコンパイラの情報使わんとロクなことできない。

ていうかまだ _ZN1C3addEii とか残ってる時点で論外。まぁ仮想関数テーブルの位置わかったしいいか…

#include <stdio.h>

#include <sys/mman.h>
#include <limits.h>
#ifndef PAGESIZE
# define PAGESIZE 4096
# define PAGESIZEMM (PAGESIZE-1)
#endif

/* 継承装置 */

void inheriter_override(void* p, void* oldfn, void* newfn) {
    void** tbl = *(void***)p;
    mprotect((void*)(((int)tbl+PAGESIZEMM) & ~PAGESIZEMM - PAGESIZE),
             PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
    while (*tbl != oldfn) tbl++;
    *tbl = newfn;
}

void* inheriter_member(void* p, int i) {
    return ((int*)p+1+i);
}

/* ベースクラス C */

class C {
public:
    void set(int v0) { v = v0; }
    virtual int add(int x, int y) { return v+x+y; }
private:
    int v;
};

/* class E を作って C::add をオーバーライドする */

/* うまく消せんかった */
extern "C" {
    int _ZN1C3addEii(C* c, int x, int y);
}

int E_add(C* c, int x, int y) {
    int* vp = (int*)inheriter_member(c, 0);
    (*vp)++;
    return _ZN1C3addEii(c, x, y);
}

C* E_new() {
    C* c = new C();
    inheriter_override(c, (void*)_ZN1C3addEii, (void*)E_add);
    return c;
}

/* 使ってみる */

int main() {
    C* c = E_new();
    c->set(1);
    printf("%d\n", c->add(2, 3));
    printf("%d\n", c->add(2, 3));
    return 0;
}
なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h