共有ライブラリの動的リンクによりインタフェースの実装を読み込むポリモーフィズム
ヘッダファイル
確認のために,C++ dlopen mini HOWTOを参考にして,ありがちなAnimalインタフェースとCatクラス及びDogクラスという設定で,Animalインタフェースの異なる実装を動的に読み込みポリモーフィズムを実現するプログラムを書いてみました.
muupan/polymorphism_dynamic_link · GitHub
main.cpp
#include <iostream> #include <cstdlib> #include <dlfcn.h> #include "animal.hpp" using std::cerr; using std::endl; using std::string; void *LoadFuncOrDie(void *lib, const string& func_name) { const auto func = dlsym(lib, func_name.c_str()); const auto dlsym_error = dlerror(); if (dlsym_error) { cerr << "Cannot load symbol create: " << dlsym_error << endl; dlclose(lib); exit(EXIT_FAILURE); } return func; } void *LoadLibOrDie(const string& path) { const auto lib = dlopen(path.c_str(), RTLD_LAZY); if (!lib) { cerr << "Cannot load library: " << dlerror() << endl; exit(EXIT_FAILURE); } return lib; } int main(int argc, char **argv) { const auto catlib = LoadLibOrDie("./cat.so"); const auto doglib = LoadLibOrDie("./dog.so"); const auto CreateCat = static_cast<AnimalCreateFunc*>(LoadFuncOrDie(catlib, "Create")); const auto CreateDog = static_cast<AnimalCreateFunc*>(LoadFuncOrDie(doglib, "Create")); { const auto& cat = CreateCat(); cat->Cry(); } { const auto& dog = CreateDog(); dog->Cry(); } dlclose(catlib); dlclose(doglib); }
animal.hpp
#ifndef ANIMAL_HPP #define ANIMAL_HPP #include <memory> using std::unique_ptr; class Animal { public: virtual ~Animal() {}; virtual void Cry() const = 0; }; typedef unique_ptr<Animal> AnimalCreateFunc(); #endif // ANIMAL_HPP
cat.cpp
#include <iostream> #include <memory> #include "animal.hpp" using std::cout; using std::endl; using std::unique_ptr; class Cat : public Animal { public: Cat() { cout << "Cat was born." << endl; } ~Cat() { cout << "Cat died." << endl; } void Cry() const override { cout << "\"Meow\"" << endl; } }; extern "C" unique_ptr<Animal> Create() { return unique_ptr<Animal>(new Cat); }
dog.cpp
#include <iostream> #include <memory> #include "animal.hpp" using std::cout; using std::endl; using std::unique_ptr; class Dog : public Animal { public: Dog() { cout << "Dog was born." << endl; } ~Dog() { cout << "Dog died." << endl; } void Cry() const override { cout << "\"Bow-wow\"" << endl; } }; extern "C" unique_ptr<Animal> Create() { return unique_ptr<Animal>(new Dog); }
動作確認にはGCC4.7.0を使用しました.main.cppの実行前にcat.cppとdog.cppをコンパイルしてcat.soとdog.soを作っておきます.
出力結果は下のようになりました.オブジェクト生成関数の返り値はどちらもstd::unique_ptr
Cat was born. "Meow" Cat died. Dog was born. "Bow-wow" Dog died.
動的リンクする共有ライブラリを切り替えればプログラムの動作を動的に変更できますし,実行時にコード生成→コンパイル→動的リンクを順に行うことでevalのようなこともできそうです.
2013/06/02追記:static_cast,overrideを使うように更新