adds "callback" and "extend" examples

This commit is contained in:
Robert Stone 2013-11-12 13:03:49 -08:00
commit 73e2de7538
14 changed files with 312 additions and 1 deletions

View file

@ -0,0 +1,20 @@
TOP = ../..
SWIG = $(TOP)/../preinst-swig
CXXSRCS = example.cxx
TARGET = example
INTERFACE = example.i
LIBS = -lm
check: build
$(MAKE) -f $(TOP)/Makefile perl5_run
build:
$(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' perl5_cpp
static:
$(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
TARGET='myperl' INTERFACE='$(INTERFACE)' perl5_cpp_static
clean:
$(MAKE) -f $(TOP)/Makefile perl5_clean

View file

@ -0,0 +1,4 @@
/* File : example.cxx */
#include "example.h"

View file

@ -0,0 +1,23 @@
/* File : example.h */
#include <cstdio>
#include <iostream>
class Callback {
public:
virtual ~Callback() { std::cout << "Callback::~Callback()" << std:: endl; }
virtual void run() { std::cout << "Callback::run()" << std::endl; }
};
class Caller {
private:
Callback *_callback;
public:
Caller(): _callback(0) {}
~Caller() { delCallback(); }
void delCallback() { delete _callback; _callback = 0; }
void setCallback(Callback *cb) { delCallback(); _callback = cb; }
void call() { if (_callback) _callback->run(); }
};

View file

@ -0,0 +1,17 @@
/* File : example.i */
%module(directors="1") example
%{
#include "example.h"
%}
%include "std_string.i"
/* turn on director wrapping Callback */
%feature("director") Callback;
/* Caller::setCallback(Callback *cb) gives ownership of the cb to the
* Caller object. The wrapper code should understand this. */
%apply SWIGTYPE *DISOWN { Callback *cb };
%include "example.h"

View file

@ -0,0 +1,20 @@
<html>
<head>
<title>SWIG:Examples:perl5:callback</title>
</head>
<body bgcolor="#ffffff">
<tt>SWIG/Examples/perl/callback/</tt>
<hr>
<H2>Implementing C++ callbacks in Perl</H2>
<p>
This example illustrates how to use directors to implement C++ callbacks.
</p>
<hr>
</body>
</html>

View file

@ -0,0 +1,40 @@
#!/usr/bin/perl
use strict;
use warnings;
use example;
{
package PerlCallback;
use base 'example::Callback';
sub run {
print "PerlCallback.run()\n";
}
}
print "Adding and calling a normal C++ callback\n";
print "----------------------------------------\n";
my $caller = example::Caller->new();
my $callback = example::Callback->new();
$caller->setCallback($callback);
$caller->call();
$caller->delCallback();
$callback = PerlCallback->new();
print "\n";
print "Adding and calling a Perl callback\n";
print "------------------------------------\n";
$caller->setCallback($callback);
$caller->call();
$caller->delCallback();
# Note that letting go of $callback will not attempt to destroy the
# object, ownership passed to $caller in the ->setCallback() call, and
# $callback was already destroyed in ->delCallback().
undef $callback;
print "\n";
print "perl exit\n";

View file

@ -4,7 +4,6 @@ constants
constants2
funcptr
import
java
multimap
multiple_inheritance
pointer
@ -12,3 +11,5 @@ reference
simple
value
variables
callback
extend

View file

@ -0,0 +1,20 @@
TOP = ../..
SWIG = $(TOP)/../preinst-swig
CXXSRCS = example.cxx
TARGET = example
INTERFACE = example.i
LIBS = -lm
check: build
$(MAKE) -f $(TOP)/Makefile perl5_run
build:
$(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' perl5_cpp
static:
$(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
TARGET='myperl' INTERFACE='$(INTERFACE)' perl5_cpp_static
clean:
$(MAKE) -f $(TOP)/Makefile perl5_clean

View file

@ -0,0 +1,4 @@
/* File : example.cxx */
#include "example.h"

View file

@ -0,0 +1,56 @@
/* File : example.h */
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
class Employee {
private:
std::string name;
public:
Employee(const char* n): name(n) {}
virtual std::string getTitle() { return getPosition() + " " + getName(); }
virtual std::string getName() { return name; }
virtual std::string getPosition() const { return "Employee"; }
virtual ~Employee() { printf("~Employee() @ %p\n", this); }
};
class Manager: public Employee {
public:
Manager(const char* n): Employee(n) {}
virtual std::string getPosition() const { return "Manager"; }
};
class EmployeeList {
std::vector<Employee*> list;
public:
EmployeeList() {
list.push_back(new Employee("Bob"));
list.push_back(new Employee("Jane"));
list.push_back(new Manager("Ted"));
}
void addEmployee(Employee *p) {
list.push_back(p);
std::cout << "New employee added. Current employees are:" << std::endl;
std::vector<Employee*>::iterator i;
for (i=list.begin(); i!=list.end(); i++) {
std::cout << " " << (*i)->getTitle() << std::endl;
}
}
const Employee *get_item(int i) {
return list[i];
}
~EmployeeList() {
std::vector<Employee*>::iterator i;
std::cout << "~EmployeeList, deleting " << list.size() << " employees." << std::endl;
for (i=list.begin(); i!=list.end(); i++) {
delete *i;
}
std::cout << "~EmployeeList empty." << std::endl;
}
};

View file

@ -0,0 +1,20 @@
/* File : example.i */
%module(directors="1") example
%{
#include "example.h"
%}
%include "std_vector.i"
%include "std_string.i"
/* turn on director wrapping for Manager */
%feature("director") Employee;
%feature("director") Manager;
/* EmployeeList::addEmployee(Employee *p) gives ownership of the
* employee to the EmployeeList object. The wrapper code should
* understand this. */
%apply SWIGTYPE *DISOWN { Employee *p };
%include "example.h"

View file

@ -0,0 +1,19 @@
<html>
<head>
<title>SWIG:Examples:perl5:extend</title>
</head>
<body bgcolor="#ffffff">
<tt>SWIG/Examples/perl5/extend/</tt>
<hr>
<H2>Extending a simple C++ class</H2>
<p>
This example illustrates the extending of a C++ class with cross language polymorphism.
<hr>
</body>
</html>

View file

@ -0,0 +1,65 @@
#!/usr/bin/perl
use strict;
use warnings;
use example;
# This file illustrates the cross language polymorphism using directors.
{
# CEO class, which overrides Employee::getPosition().
package CEO;
use base 'example::Manager';
sub getPosition {
return 'CEO';
}
}
# Create an instance of CEO, a class derived from the Java proxy of the
# underlying C++ class. The calls to getName() and getPosition() are standard,
# the call to getTitle() uses the director wrappers to call CEO.getPosition().
my $e = CEO->new('Alice');
print "${\ $e->getName } is a ${\ $e->getPosition() }\n";
print "Just call her \"${\ $e->getTitle() }\"\n";
print "----------------------\n";
# Create a new EmployeeList instance. This class does not have a C++
# director wrapper, but can be used freely with other classes that do.
my $list = example::EmployeeList->new();
$list->addEmployee($e);
print "----------------------\n";
# Now we access the first four items in list (three are C++ objects that
# EmployeeList's constructor adds, the last is our CEO). The virtual
# methods of all these instances are treated the same. For items 0, 1, and
# 2, all methods resolve in C++. For item 3, our CEO, getTitle calls
# getPosition which resolves in Perl. The call to getPosition is
# slightly different, however, because of the overidden getPosition() call, since
# now the object reference has been "laundered" by passing through
# EmployeeList as an Employee*. Previously, Perl resolved the call
# immediately in CEO, but now Perl thinks the object is an instance of
# class Employee. So the call passes through the
# Employee proxy class and on to the C wrappers and C++ director,
# eventually ending up back at the Perl CEO implementation of getPosition().
# The call to getTitle() for item 3 runs the C++ Employee::getTitle()
# method, which in turn calls getPosition(). This virtual method call
# passes down through the C++ director class to the Perl implementation
# in CEO. All this routing takes place transparently.
print "(position, title) for items 0-3:\n";
print " ${\ $list->get_item(0)->getPosition() }, \"${\ $list->get_item(0)->getTitle() }\"\n";
print " ${\ $list->get_item(1)->getPosition() }, \"${\ $list->get_item(1)->getTitle() }\"\n";
print " ${\ $list->get_item(2)->getPosition() }, \"${\ $list->get_item(2)->getTitle() }\"\n";
print " ${\ $list->get_item(3)->getPosition() }, \"${\ $list->get_item(3)->getTitle() }\"\n";
print "----------------------\n";
# Time to delete the EmployeeList, which will delete all the Employee*
# items it contains. The last item is our CEO, which gets destroyed as well.
undef $list;
print "----------------------\n";
# All done.
print "perl exit\n";

View file

@ -20,6 +20,8 @@ certain C declarations are turned into constants.
<li><a href="reference/index.html">reference</a>. C++ references.
<li><a href="pointer/index.html">pointer</a>. Simple pointer handling.
<li><a href="funcptr/index.html">funcptr</a>. Pointers to functions.
<li><a href="callback/index.html">callback</a>. C++ callbacks using directors.
<li><a href="extend/index.html">extend</a>. Extending a simple C++ class.
</ul>
<h2>Compilation Issues</h2>