Boost.Python is a powerful library that enables seamless integration between C++ and Python. It allows C++ functions and classes to be exposed to Python, enabling direct interaction between the two languages.
As I was playing around with Boost.Python, I made my existing Factory Pattern project written in C++ to expose itself to the python using Boost.Python library.
The most important part is the following lines of code. This is kind of self explanatory - how we expose the C++ classes and methods to Python code.
// Expose Singleton Factory to Python
BOOST_PYTHON_MODULE(FactoryPattern) {
using namespace boost::python;
class_<Food, boost::noncopyable>("Food", no_init)
.def("getName", pure_virtual(&Food::getName));
class_<Biscuit, bases<Food>>("Biscuit")
.def("getName", &Biscuit::getName); // Ensure Biscuit has getName
class_<Chocolate, bases<Food>>("Chocolate")
.def("getName", &Chocolate::getName); // Ensure Chocolate has getName
class_<Factory, boost::noncopyable>("Factory", no_init)
.def("getInstance", &Factory::getInstance, return_value_policy<reference_existing_object>())
.staticmethod("getInstance")
.def("makeFood", &Factory::makeFood, return_value_policy<manage_new_object>());
}
Here's the complete source code of the C++ Factory Pattern... We will have to make a shared object (so) from this C++ project.
/*
* Food.h
*
* Created on: Mar 10, 2021
* Author: som
*/
#ifndef FOOD_H_
#define FOOD_H_
#include <string>
using namespace std;
class Food {
public:
virtual string getName() = 0;
virtual ~Food(){
}
};
#endif /* FOOD_H_ */
/*
* Chocolate.h
*
* Created on: Mar 10, 2021
* Author: som
*/
#ifndef CHOCOLATE_H_
#define CHOCOLATE_H_
#include <iostream>
#include "Food.h"
class Chocolate: public Food {
public:
Chocolate();
virtual ~Chocolate();
string getName();
};
#endif /* CHOCOLATE_H_ */
/*
* Chocolate.cpp
*
* Created on: Mar 10, 2021
* Author: som
*/
#include "Chocolate.h"
Chocolate::Chocolate() {
// TODO Auto-generated constructor stub
cout<<"Chocolate is made..."<<endl;
}
Chocolate::~Chocolate() {
// TODO Auto-generated destructor stub
}
string Chocolate::getName(){
return "It's a Chocolate";
}
/*
* Biscuit.h
*
* Created on: Mar 10, 2021
* Author: som
*/
#ifndef BISCUIT_H_
#define BISCUIT_H_
#include "Food.h"
class Biscuit: public Food {
public:
Biscuit();
string getName();
~Biscuit();
};
#endif /* BISCUIT_H_ */
/*
* Biscuit.cpp
*
* Created on: Mar 10, 2021
* Author: som
*/
#include <iostream>
#include "Biscuit.h"
using namespace std;
Biscuit::Biscuit() {
// TODO Auto-generated constructor stub
cout<<"Biscuit is made..."<<endl;
}
Biscuit::~Biscuit(){}
string Biscuit::getName(){
return "It's a Biscuit";
}
/*
* Factory.h
*
* Created on: Mar 10, 2021
* Author: som
*/
#ifndef FACTORY_H_
#define FACTORY_H_
#include <boost/python.hpp>
#include <iostream>
#include <string>
#include "Biscuit.h"
#include "Chocolate.h"
using namespace std;
class Factory{
public:
static Factory* instance;
static Factory* getInstance();
Food* makeFood(const string& type);
private:
Factory(){}
// Delete copy constructor & assignment operator (Singleton pattern)
Factory(const Factory&) = delete;
Factory& operator=(const Factory&) = delete;
};
#endif /* FACTORY_H_ */
/*
* Factory.cpp
*
* Created on: Jan 30, 2025
* Author: som
*/
#include "Factory.h"
Factory* Factory::instance = NULL;
Factory* Factory:: getInstance(){
if(Factory::instance == NULL){
Factory::instance = new Factory();
}
return Factory::instance;
}
Food* Factory::makeFood(const string& type){
if(type.compare("bi") == 0){
return new Biscuit();
}
if(type.compare("ch") == 0){
return new Chocolate();
}
return NULL;
}
// Expose Singleton Factory to Python
BOOST_PYTHON_MODULE(FactoryPattern) {
using namespace boost::python;
class_<Food, boost::noncopyable>("Food", no_init)
.def("getName", pure_virtual(&Food::getName));
class_<Biscuit, bases<Food>>("Biscuit")
.def("getName", &Biscuit::getName); // Ensure Biscuit has getName
class_<Chocolate, bases<Food>>("Chocolate")
.def("getName", &Chocolate::getName); // Ensure Chocolate has getName
class_<Factory, boost::noncopyable>("Factory", no_init)
.def("getInstance", &Factory::getInstance, return_value_policy<reference_existing_object>())
.staticmethod("getInstance")
.def("makeFood", &Factory::makeFood, return_value_policy<manage_new_object>());
}
Here's the project settings for the C++ code...
And here's the python script to access the C++ methods.
import FactoryPattern
factory = FactoryPattern.Factory.getInstance()
biscuit = factory.makeFood("bi")
print(biscuit.getName()) # Expected: "Biscuit"
chocolate = factory.makeFood("ch")
print(chocolate.getName()) # Expected: "Chocolate"
Here's a short video showing the output in a Python workspace...
By the way... there is another way to connect your Python code
to C++ - that is SWIG...
I explored SWIG sometimes back.
Here we go...