Overriding virtual C++ method in Ruby

T

Tobias Grimm

Hi!

Slowly but surly, I'm getting my foot on the ground with embedding Ruby in a C++
application.

So far I can call methods of C++ -classes from the ruby script (using SWIG) and
ruby-stuff from C++ using rb_eval_string_protect.

Now I would like to derive a C++-Class in a Ruby script, override a virtual
method of the C++ class, return an instance of this new class back to C++ and
then invoke the overridden method. I've no idea, if this is possible at all.

See this example and what happens:

[C++:]

class Foo
{
public:
virtual char *bar(void) { return "C++ implementation" };
};

[Ruby:]

class FooBar < MyModul::Foo
def bar
return "Ruby implementation"
end
end

test = Foo.new
$uglyGlobal = FooBar.new

STDERR.puts("Ruby-Foo: ", test.bar)
STDERR.puts("Ruby-FooBar: ", $uglyGlobal.bar)

[Back in C++:]

// ...
// initializing ruby and making SWIG-wrapper available
// ...

rb_load_protect(rb_str_new2("test.rb"), Qfalse, &state);
VALUE obj = rb_eval_string_protect("$uglyGlobal", &state);

Foo fooFromCpp = new Foo();
Foo fooFromRuby = *reinterpret_cast<Foo *>(obj);

cerr << "C++-Foo: " << fooFromCpp.bar() << endl;
cerr << "C++-FooBar: " << fooFromRuby.bar() << endl;

[The output is:]

Ruby-Foo: C++ implementation
Ruby-FooBar: Ruby implementation
C++-Foo: C++ implementation
C++-FooBar: C++ implementation

Obviously C++ does not see, that the FooBar object returned by Ruby has
overriden bar(). Am I doing something completely wrong?

I'm not sure how polymorphism is implemented in gcc, but I'm afraid something
like this is simply not possible, is it?

bye,

Tobias
 
L

Lyle Johnson

T

Tobias Grimm

Lyle said:
Please read up on SWIG's cross-language polymorphism feature (a.k.a.
the "directors" feature), described here:

Thanks for the hint, I missed this. But when enabling the directors feature
some errors are raised.

Very simple example:

[foo.cc]
class Foo
{
public:
virtual char *test(void)
{
return "C++ implementation";
}
virtual ~Foo() {};
};


[foo.i]
%module(directors="1") ModFoo

%feature("director") Foo;

%include "foo.cc"


[bar.rb]
class Bar < ModFoo::Foo
def test
p "ruby implementation of test called"
return "Ruby Implementation"
end
end

$foo2 = Bar.new


[main.cc]
int main()
{
int state;

ruby_init();
ruby_init_loadpath();
SWIG_init();

rb_load_protect(rb_str_new2("bar.rb"), Qfalse, &state);
checkRubyError(state);

Foo *foo1 = new Foo();
Foo *foo2;


VALUE obj = rb_eval_string_protect("$foo2", &state);
checkRubyError(state);

rb_p(obj);

Data_Get_Struct(obj, Foo, foo2);

cout << "calling C++ implementation : " << foo1->test() << endl;
cout << "calling Ruby implementation: " << foo2->test() << endl;

ruby_finalize();
return 0;
}

[Output - directors feature disabled]
#<Bar:0x402c5db8>
calling C++ implementation : C++ implementation
calling Ruby implementation: C++ implementation

[Output - directors feature enabled]
#<Bar:0x402c5c8c>
calling C++ implementation : C++ implementation
"ruby implementation of test called"
(eval): wrong argument type String (expected Data) (TypeError)
(eval): [BUG] Segmentation fault
ruby 1.8.1 (2004-02-03) [i386-linux]

Where can the problem be? the test() implementation of the Ruby Bar-class gets
called, but then something seems to go wrong with returning the string value.

Tobias
 
T

Tobias Grimm

Tobias said:
Where can the problem be? the test() implementation of the Ruby
Bar-class gets called, but then something seems to go wrong with
returning the string value.

I figured out, that the following typemap will solve the problem:

%typemap(directorout) char * {
$result = STR2CSTR($1);
}


Tobias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,156
Messages
2,570,878
Members
47,406
Latest member
ElizabetMo

Latest Threads

Top