• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
C++ API 디자인 - 확장성
 

C++ API 디자인 - 확장성

on

  • 251 views

 

Statistics

Views

Total Views
251
Views on SlideShare
251
Embed Views
0

Actions

Likes
0
Downloads
0
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    C++ API 디자인 - 확장성 C++ API 디자인 - 확장성 Presentation Transcript

    • C++
    •   API
    •   Design
    •    Ch.12
    •   확장성 Cecil
    • In
    •   this
    •   chapter •Plugin
    •    •상속
    •    •템플릿
    • Plugin
    • 플러그인을
    •   통한
    •   확장
    •   방법 12.1.1 Plugin Model Overview Many examples of commercial software packages allow their core functionality to be extended API Code API PLUGIN API Library Plugin Code Plugin Library Compiler Compiler FIGURE 12.1 A plugin library is a dynamic library that can be compiled separately from a Core API and explicitly loaded by the API on demand. 362 CHAPTER 12 Extensibility 핵심
    •   API와
    •   별개로
    •   컴파일
    •   되며,
    •   필요시
    •   로드되어
    •   사용
    • 플러그인
    •   사용
    •   예:
    •   world
    •   of
    •   warcraft
    • 플러그인
    •   사용시
    •   이점 다재다능한
    •   능력,
    •   커뮤니티
    •   활성화
    •    업데이트
    •   간소화,미래
    •   경쟁력
    •   강화
    •    리스크
    •   격리화
    • 일반적인
    •   플러그인
    •   시스템
    •   구조 플러그인
    •   매니저:
    •   플러그인
    •   수명
    •   주기를
    •   관리하는
    •   API
    •   코드
    •    플러그인
    •   API:
    •   플러그인을
    •   만들기
    •   위해서
    •   사용자가
    •   컴파일하는
    •   API 12.1.2 Plugin System Design Issues There are many different ways to design a plugin system. The best solution for your current project may not be the best choice for your next project. I will therefore start by trying to tease out some of the high-level issues that you should be aware of when devising a plugin system. At the same time, there are also a number of general concepts applicable to all plugin systems. For example, when supporting dynamic library plugins, you will always need a mechanism to load a dynamic library and access symbols in that file. In general, when creating any plugin system, there are two major features that you must design (see Figure 12.2). 1. The Plugin API: This is the API that your users must compile and link against in order to create a plugin. I differentiate this from your Core API, which is the larger code base into which you are adding the plugin system. 2. The Plugin Manager: This is an object (often a singleton) in the Core API code that manages the Plugin 1 Core API Plugin Manager Plugin 2 Plugin 2 FIGURE 12.2 The Plugin Manager lives in the Core API. It discovers and loads plugins that have been built against the Plugin API.
    • 플러그인
    •   설계시
    •   고려사항
    •   In
    •   C++ C++
    •   vs
    •   C,
    •   버전
    •   관리
    •    내부
    •   vs
    •   외부
    •   메타
    •   데이터
    •    일반화
    •   vs
    •   특화된
    •   플러그인
    •   매니저
    •    보안,
    •   정적
    •   vs
    •   동적
    •   라이브러리
    • C++로
    •   플러그인
    •   개발시
    •   이슈 플러그인
    •   개발자는
    •   API와
    •   같은
    •   컴파일러
    •   버전을
    •   사용해야
    •   함
    •    or
    •   바인딩
    •   기술
    •   도입이
    •   필요(COM,
    •   IPC
    •   …⋯)
    • C++만
    •   사용해서
    •   해결하려면? 추상화
    •   베이스
    •   클래스
    •   사용
    •    자유
    •   함수를
    •   위한
    •   C
    •   링크
    •   사용
    •   (extern)
    •    STL
    •   및
    •   예외
    •   사용
    •   금지
    •    혼합
    •   할당자
    •   사용
    •   금지
    • 플러그인
    •   API
    •   개발
    •   방법 플러그인
    •   등록시
    •   콜백
    •   구조체를
    •   등록
    •    or
    •   플러그인을
    •   실행하기
    •   위해
    •   호출하는
    •   함수의
    •   이름을
    •   fix
    • 구조체
    •   Callback 12.1.4 The Plugin API The Plugin API is the interface that you provide to your users to create plugins. I’ll call it pluginapi.h in our example here. This header file will contain functionality that allows plugins to communicate with the Core API. When the Core API loads a plugin, it needs to know which functions to call or symbols to access in order to let the plugin do its work. This means that you should define specifically named entry points in the plugin that your users must provide. There are several different ways that you can do this. For example, when writing a GIMP plugin, you must define a variable called PLUG IN INFO that lists the various callbacks defined in the plugin. #include <libgimp/gimp.h> GimpPlugInInfo PLUG IN INFO { NULL, /* called when GIMP starts */ NULL, /* called when GIMP exits */ query, /* procedure registration and arguments definition */ run, /* perform the plugin’s operation */ }; Netscape Plugins use a similar, although slightly more flexible, technique. In this case, plugin wri- ters define an NP GetEntryPoints() function and fill in the appropriate fields of the NPPluginFuncs structure that the browser passes in during plugin registration. The NPPluginFuncs structure includes size and version fields to handle future expansion. Another solution is to have specifically named functions that the Core API can call, if they are exported by the plugin. I will adopt this approach for our example because it is simple and scalable; for example, it doesn’t rely on a fixed size array or structure. The two most basic callbacks that a plugin should provide are an initialization function and a cleanup 36712.1 Extending via plugins 플러그인
    •   등록시
    •   콜백
    •   구조체를
    •   등록
    • 호출하는
    •   함수
    •   이름을
    •   fix 동적
    •   로딩시
    •   정해진
    •   심볼을
    •   찾아
    •   플러그인
    •   호출
    •    ex)
    •   PluginInit,
    •   PluginFree // pluginapi.h #include "defines.h" #include "renderer.h" #define CORE_FUNC extern "C" CORE_API #define PLUGIN_FUNC extern "C" PLUGIN_API #define PLUGIN_INIT() PLUGIN_FUNC int PluginInit() #define PLUGIN_FREE() PLUGIN_FUNC int PluginFree() typedef IRenderer *(*RendererInitFunc)(); typedef void (*RendererFreeFunc)(IRenderer *); CORE_FUNC void RegisterRenderer(const char *type, RendererInitFunc init cb, RendererFreeFunc free cb);
    • 플러그인
    •   예제
    •   코드 // plugin1.cpp 
 #include "pluginapi.h" 
 #include <iostream>
 class OpenGLRenderer : public IRenderer {
 public:
 ~OpenGLRenderer() {}
 bool LoadScene(const char *filename) { return true; }
 void SetViewportSize(int w, int h) {}
 void SetCameraPosition(double x, double y, double z) {}
 void SetLookAt(double x, double y, double z) {}
 void Render() { std::cout << "OpenGL Render" << std::endl; } };
 PLUGIN_FUNC IRenderer *CreateRenderer() {
 return new OpenGLRenderer(); 
 }
 PLUGIN_FUNC void DestroyRenderer(IRenderer *r) {
 delete r; 
 }
 PLUGIN_INIT() {
 RegisterRenderer("opengl", CreateRenderer, DestroyRenderer);
 return 0; 
 } // renderer.h 
 #include <string>
 class IRenderer {
 public:
 virtual ~IRenderer() {}
 virtual bool LoadScene(const char *filename) = 0;
 virtual void SetViewportSize(int w, int h) = 0;
 virtual void SetCameraPosition(double x, double y, double z) = 0;
 virtual void SetLookAt(double x, double y, double z) = 0;
 virtual void Render() = 0; 
 }; 플러그인
    •   수정
    •   없이
    •   
    •    플러그인
    •   매니저
    •   수정을
    •   위해
    •    별도의
    •   함수를
    •   제공
    • 플러그인
    •   매니저
    •   코드 // pluginmanager.cpp #include "defines.h" #include <string> #include <vector> class CORE API PluginInstance { public: explicit PluginInstance(const std::string &name); ~PluginInstance(); bool Load(); bool Unload(); bool IsLoaded(); std::string GetFileName(); std::string GetDisplayName(); private: PluginInstance(const PluginInstance &); const PluginInstance &operator (const PluginInstance &); class Impl;
 Impl *mImpl; }; class CORE_API PluginManager {
 public: static PluginManager &GetInstance(); bool LoadAll();
 bool Load(const std::string &name); bool UnloadAll(); bool Unload(const std::string &name); std::vector<PluginInstance *> GetAllPlugins(); private:
 PluginManager();
 ~PluginManager();
 PluginManager(const PluginManager &);
 const PluginManager &operator (const PluginManager &); std::vector<PluginInstance *> mPlugins; }; 메타
    •   데이터를
    •   관리하고,
    •   라이브러리를
    •   로드/언로드
    •    주로
    •   싱글톤으로
    •   구현됨
    • 플러그인
    •   버전
    •   관리 핵심
    •   API
    •   버전과
    •   동일하게
    •   관리
    •    or
    •   플러그인
    •   API
    •   버전을
    •   따로
    •   관리
    •    사용자는
    •   플러그인이
    •   어떤
    •   버전과
    •   호환이
    •   되는지
    •   명시
    •   해야
    •   함.
    • 상속
    • 상속을
    •   통한
    •   확장 기능
    •   추가:
    •   클래스를
    •   상속
    •   받아
    •   하위
    •   클래스에서
    •   기능
    •   추가
    •    베이스
    •   클래스가
    •   상속을
    •   염두에
    •   두고
    •   설계
    •   되어야
    •   함.
    •   (가상
    •   소멸자)
    •    ! 기능
    •   수정:
    •   하위
    •   클래스에서
    •   오버라이드하여
    •   기능을
    •   수정
 (templete
    •   method)
    • 상속과
    •   STL STL
    •   컨데이터
    •   클래스는
    •   가상
    •   소멸자를
    •   제공하지
    •   않음.
    •    STL
    •   컨데이터
    •   클래스는
    •   상속
    •   받지
    •   않는
    •   것이
    •   규칙
    • Visitor of methods that operate on every node in a scene graph hierarchy or to traverse the derivation tree of a programming language parser and output a human-readable form of the program. Let’s develop a visitor example to illustrate how this pattern works. I’ll use the example of a scene graph hierarchy that describes a 3D scene, such as that used by Open Inventor, OpenSceneGraph, or the Virtual Reality Modeling Language. To keep the example simple, our scene graph will contain only three different node types: Shape, Transform, and Light. Figure 12.4 shows an example hierarchy using these node types. I’ll begin by defining our abstract visitor interface. Clients can create concrete subclasses of this interface in order to add custom operations to the scene graph. It essentially declares a Visit() method for each node type in the scene graph. // nodevisitor.h class ShapeNode; class TransformNode; class LightNode; class INodeVisitor { public: Transform0 Transform1 Transform2 Shape0 Shape1 Shape2 Light0 FIGURE 12.4 Example scene graph hierarchy showing nodes of different types. 37912.2 Extending via inheritance 이전의
    •   데이터
    •   구조에
    •   변경
    •   없이
    •   새로운
    •   기능
    •   추가가
    •   가능 { public: SceneGraph(); SceneGraph(); void Traverse(INodeVisitor &visitor); private: SceneGraph(const SceneGraph &); const SceneGraph &operator =(const SceneGraph &); class Impl; Impl *mImpl; }; Note that each of the node types declares an Accept() method, taking a visitor object as its parameter. This method is used to call the appropriate Visit() method in the visitor class. This can be thought of as a way to have a single virtual method in each node that can then call any user-supplied virtual method. See Figure 12.5 for a UML diagram that shows this Visitor pattern. // scenegraph.cpp void ShapeNode::Accept(INodeVisitor &visitor) { visitor.Visit(*this); } << interface >> << interface >> BaseNode NodeA NodeB Visitor + Accept(visitor: Visitor) : void + Accept(visitor: Visitor) : void+ Accept(visitor: Visitor) : void + Visit(node: NodeA) : void + Visit(node: NodeB) : void FIGURE 12.5 UML diagram of the Visitor design pattern. 38112.2 Extending via inheritance
    • Visitor
    •   Code // scenegraph.h #include <string> class INodeVisitor; class BaseNode {
 public: explicit BaseNode(const std::string &name); virtual ~BaseNode() {}
 virtual void Accept(INodeVisitor &visitor) = 0; private:
 std::string mName; }; class ShapeNode : public BaseNode {
 public: explicit ShapeNode(const std::string &name); void Accept(INodeVisitor &visitor);
 }; class TransformNode : public BaseNode {
 public: explicit TransformNode(const std::string &name); void Accept(INodeVisitor &visitor); }; ! // scenegraph.cpp
 void ShapeNode::Accept(INodeVisitor &visitor) { visitor.Visit(*this); } void TransformNode::Accept(INodeVisitor &visitor) { visitor.Visit(*this); } // nodevisitor.h class ShapeNode; class TransformNode; class LightNode; class INodeVisitor {
 public: virtual ~INodeVisitor() {} virtual void Visit(ShapeNode &node) = 0; virtual void Visit(TransformNode &node) = 0; virtual void Visit(LightNode &node) = 0; }; visitor에
    •   따라
    •   다른
    •   기능을
    •   수행
    • Visitor
    •   패턴의
    •   특징 데이터
    •   구조의
    •   수정
    •   없이
    •   새로운
    •   기능
    •   추가
    •   가능.
    •    일관된
    •   연산을
    •   수행하는
    •   코드를
    •   한
    •   곳에
    •   위치
    •   시킬수
    •   있음.
    •    But,
    •   새로운
    •   노드의
    •   추가는
    •   전체
    •   visitor의
    •   변경을
    •   필요.
    • 상속을
    •   제한하는
    •   방법
    •   in
    •   c++ 생성자를
    •   private로
    •   선언
    •    (클래스
    •   인스턴스를
    •   stack에
    •   생성
    •   불가)
    •    ! 가상
    •   상속을
    •   이용한
    •   방법 class NonBaseFinal {
 private:
 NonBaseFinal() {}
 friend class NonBase; 
 }; class NonBase :virtual public NonBaseFinal {
 …
 };
    • 템플릿
    • 정책
    •   기반
    •   템플릿 정책이라
    •   불리는
    •   작은
    •   클래스를
    •   통한
    •   복잡한
    •   행동을
    •   구현하는
    •   접근법 template<
 typename T,
 template <class> class OwnershipPolicy = RefCounted, 
 class ConversionPolicy = DisallowConversion,
 template <class> class CheckingPolicy AssertCheck, 
 template <class> class StoragePolicy DefaultSPStorage
 > class SmartPtr; 각각은
    •   다양한
    •   정책을
    •   명시 많은
    •   수의
    •   템플릿
    •   파라미터를
    •   통해
    •   코드를
    •   작성하는
    •   일은
    •   쉽지
    •   않음.
    • 정교하게
    •   반복되는
    •   템플릿 template <typename T> class Base; class Derived : public Base<Derived>; 베이스
    •   클래스가
    •   파생
    •   클래스의
    •   네임스페스에
    •   접근
    •   가능 런타임시
    •   가상
    •   메서드를
    •   호출할때
    •   발생하는
    •   오버헤드를
    •   피할수
    •   있음.
    • References •Martin
    •   Reddy
    •   (2014).
    •   C++
    •   API
    •   디자인.
    •   (천호민,
    •   옮김).
    •   고 양시:
    •   지앤선.
    •   (원서출판
    •   2013)