2014-01-13 4 views
2

저는 크로스 플랫폼을 목표로하는 프로그램을 작성하고 있습니다. 따라서 특정 작업의 여러 구현을 지원할 것입니다. 나의 첫 번째 아이디어는 공용 인터페이스와 함께 각 플랫폼에 대한 추상적 인 팩토리를 사용하여 클래스의 계층 구조를 작성하는 것이 었습니다.크로스 플랫폼 구현을 추상화하는 일반적인 관용구는 무엇입니까?

class Operation { 
    DoOperation() = 0; 
} 

class OperationPlatform1 : public Operation { 
    DoOperation(); 
} 

class OperationPlatform2 : public Operation { 
    DoOperation(); 
} 

#ifdef USING_PLATFORM1 
    Operation *op = new OperationPlatform1; 
#endif 

그러나 구현시 사용되는 구현은 컴파일 타임에 알 수 있습니다. 하나가 될 것입니다있는, 추상적 인 다수의 구현에 좋은 방법은 무엇

class OperationPlatform1 { 
    DoOperation(); 
} 

class OperationPlatform2 { 
    DoOperation(); 
} 

#ifdef USING_PLATFORM1 
typedef OperationPlatform1 Operation; 
#endif 

Operation op; 

: 나는 나는 이러한 라인을 따라 뭔가를 쓸 수 있다는 것을 깨달았 후, 나는이 사용하는 정적 다형성을 구현할 수있는 방법을 생각하려고 노력 컴파일 타임에 선택 했습니까? 필자는 성능에 대해서도 관심이 있으므로 가상화 방법을 사용하지 않으려면 사용하지 않는 것이 좋습니다.

+0

표준 C++을 독점적으로 사용합니다. – PlasmaHH

답변

4

일반적인 솔루션은 를 컴파일의 헤더에 단지 하나 개의 클래스를 정의하고 그것을 다른 소스 파일을 제공하는 것입니다 어느 쪽이든 필요한 연결. 클래스 정의에 종속성 (예 : 데이터 유형)이 필요하면 각 플랫폼에 대한 특정 헤더 파일을 만들고이를 포함하여 도이를 수행 할 수 있습니다. 가장 간단한 해결책은 여기 입니다. 타겟 플랫폼 당 디렉토리를 생성하고 의 플랫폼 종속 파일을 여기에 넣어//I을 사용하여 을 올바른 디렉토리 (올바른 플랫폼 종속 파일)를 컴파일 타임에 선택하십시오. .

#ifdef을 과도하게 사용하면 디자인이 좋지 않습니다. https://www.usenix.org/legacy/publications/library/proceedings/sa92/spencer.pdf을 참조하십시오.

0

예를 들어 Qt와 같은 기존의 멀티 플랫폼 프레임 워크를 살펴보십시오. 당신은 몇 가지 옵션을 가지고 PIMPL idiom

+1

각 구현에 대해 별도의 소스 파일이있는 컴파일 방화벽 관용구는 매우 좋습니다. –

2

사용

  1. 를 사용하여 귀하의 질문에 설명 된 접근 방식은. 그러나 플랫폼 별 비트를 별도의 파일로 분할하고 빌드 규칙을 사용하여 플랫폼에 맞는 파일을 가져와야 할 가능성이 있습니다.

  2. 클래스가 하나 뿐이므로 #ifdef을 사용하여 해당 플랫폼에 맞는 코드를 삽입하십시오.

  3. 이미 플랫폼 특정 비트를 래핑 할 수있는 기존 래퍼 라이브러리 (예 : 부스트)를 사용하고 래퍼에 대해 코드를 작성하십시오.

다양한 플랫폼을 캡슐화하려는 경우 추상화가 구현에 누출되지 않도록해야합니다. 종종 세 가지 항목을 조합하여 사용하게됩니다.

2

여기에있는 내용이 일반적으로 사용됩니다. 동시에 여러 구현을 할 수 없다는 것을 절대적으로 알고 있다면, 단일 헤더 파일을 사용하고 조건부로 컴파일 된 구현 파일 (cpp)을 갖거나 일부 코드 (다른 플랫폼)를 컴파일에서 제외시키는 플랫폼 사전 컴파일러 지시문을 사용할 수 있습니다.

당신은 당신의 헤더에 수 :

class Operation { 
    DoOperation(); 
} 

그리고 여러 CPP 당신이 빌드에서 파일을 제외 할 수 있습니다에서 :

Platform1.cpp

Operation::DoOperation() { // Platform 1 implementation } 

및 PLATFORM2을.CPP

Operation::DoOperation() { // Platform 2 implementation } 



아니면 하나의 구현 파일 : 당신은 파일을 exluding 엉망으로

#ifdef PLATFORM1 
    Operation::DoOperation() { // Platform 1 implementation } 
elseif defined(PLATFORM2) 
    Operation::DoOperation() { // Platform 2 implementation } 
#endif 



또는 2의 혼합하지 않으려면 빌드 :

Platform1.cpp :

#ifdef PLATFORM1 
    Operation::DoOperation() { // Platform 1 implementation } 
#endif 

및 Platform2.cpp는 :

#ifdef PLATFORM2 
    Operation::DoOperation() { // Platform 2 implementation } 
#endif 
1

원하는 것은 소스 코드를 깨끗하게 유지하면서 다른 플랫폼을 지원하는 것입니다. 따라서 첫 번째 아이디어처럼 인터페이스에 따라 platfom 의존성을 추상화해야합니다.

동시에 #ifdef를 사용하여 구현할 수 있습니다. 예를 들어, 파일 시스템 기능은 플랫폼에 따라 크게 달라 지므로 이와 같은 파일 시스템 인터페이스를 정의하십시오.

IFileSystem& GetFileSystem() { 
    #ifdef WINDOWS 
     return WindowsFileSystemInstance; 
    #endif 
    #ifdef LINUX 
     return LinuxFileSystemInstance; 
    #endif 
    // etc. 
} 

GetFileSystem().CopyFile("dest", "source"); 

: 소스 코드는 파일 시스템 기능을 필요로하는 경우

class IFileSystem { 
public: 
    void CopyFile(const string& destName, const string& sourceName); 
    void DeleteFile(const string& name); 
    // etc. 
}; 

그런 다음 WindowsFileSystem, LinuxFileSystem, SolarisFileSystem 등의 구현을 가질 수

지금, 당신은이 같은 요청 된 인터페이스에 액세스 할 이 접근법은 응용 프로그램 논리 및 플랫폼 종속성에 대한 관심을 분리하는 데 도움이됩니다.

게터 기능의 또 다른 이점은 파일 시스템 구현을위한 런타임 선택을 할 수 있다는 것입니다. Fat32FileSystem, NtfsFileSystem, Ext3FileSystem 등