2015-01-05 2 views
0

사용자 확장을 위해 C++로 DLL을 작성할 수 있도록 사용자에게 SDK를 제공합니다.C++에서 추상 클래스 인터페이스의 서브 클래 싱 방지

SDK 헤더에는 대부분 인터페이스 클래스 정의가 포함되어 있습니다. 이 클래스는 두 가지 유형의 수 있습니다 : 사용자가 서브 클래스 다음 인수로 사용할 수있는 포인터로 DLL 함수에 응용 프로그램에 의해 전달 된 핵심 클래스 래퍼

  • 일부를 구현해야

    • 일부 핵심 기능을 호출하기위한 DLL 코드. 이러한 인터페이스는 특정 핵심 하위 클래스를 예상하므로 사용자가 하위 클래스로 분류하여 핵심 함수로 전달해서는 안됩니다.

    설명서에서 서브 클래 싱하지 않아야하는 인터페이스를 쓰고 앱에서 제공하는 객체의 포인터를 통해서만 사용합니다. 그러나 어떤 곳에서는 매뉴얼을 읽지 않는다면 SDK에서 하위 클래스를 유혹하려고합니다.

    SDK 헤더의 일부 인터페이스를 서브 클래 싱하지 못하게 할 수 있습니까?

  • +0

    [C++ 11에는 최종 키워드가 있습니다.] (http://en.cppreference.com/w/cpp/language/final) – Borgleader

    +0

    ... final final? – Wintermute

    +0

    핵심 문제는 자신의 구현에서 서브 클래 싱해야 할 필요가 있다는 것입니다. 따라서 기본적으로 구현자는 호출자와 다른 선언을보아야합니다. (예 : '최종'또는 사설 CTor). reinterpret_cast를 사용하여 대부분의 구현에서 가능 합니다만, 한계 이익을 지닌 추한 해킹이 될 것이므로 필자는 반대합니다. – peterchen

    답변

    0

    클라이언트가 을 다시 DLL로 전달하는 데 포인터를 사용할 필요가없는 한 앞으로 선언을 사용할 수 있습니다. 불완전한 유형에서 파생 될 수 없습니다. (최근에 비슷한 케이스에 직면했을 때 나는 돼지 고기를 다 먹었고 을 기준으로 을 특수 포장 형식으로 설계했습니다. 인터페이스 코드에 캐스팅이 많이 있지만, 클라이언트가 값은 날입니다.)

    해당 클래스가 클라이언트가 사용해야하는 인터페이스를 구현하는 경우 도 두 가지 해결책이 있습니다. 첫 번째는 이것을 변경하는 것입니다. 각 멤버 함수를 에 포인터를 사용하는 자유 함수로 바꾸고 앞으로 선언 만하면됩니다. ClientVisibleInterface에서 직접 파생 이 가능하지만, 그것은 불가능 최초의 :

    class InternallyVisibleInterface : public ClientVisibleInterface 
    { 
    protected: 
        InternallyVisibleInterface() {} 
    
        // And anything else you need. If there is only one class in 
        // your application which should derive from the interface, 
        // this is it. If there are several, they should derive from 
        // this class, rather than ClientVisibleInterface, since this 
        // is the only class which can construct the 
        // ClientVisibleInterface base class. 
    }; 
    
    void ClientVisibleInterface::something() 
    { 
        assert(dynamic_cast<InternallyVisibleInterface*>(this) != nullptr); 
        doSomething(); 
    } 
    

    이 두 가지 수준의 보호를 제공합니다

    class InternallyVisibleInterface; 
    
    class ClientVisibleInterface 
    { 
    private: 
        virtual void doSomething() = 0; 
        ClientVisibleInterface() = default; 
        friend class InternallyVisibleInterface; 
    protected:  // Or public, depending on whether the client should 
           // be able to delete instances or not. 
        virtual ~ClientVisibleInterface() = default; 
    public: 
        void something(); 
    }; 
    

    하고 DLL에서 다음 두 번째는 같은 것을 사용하는 것입니다 결과 클래스는 생성자를 가지므로 을 인스턴스화 할 수 없습니다. 둘째, 클라이언트 코드가 어떻게 든 속이면 런타임 오류가 발생합니다.

    두 보호가 모두 필요하지 않을 수도 있습니다. 하나 또는 다른 사람 충분해야합니다. 개인 생성자는 런타임 오류가 아닌 컴파일 시간 오류 이됩니다. 반면에, 그것 없이는 은 분산 헤더에 InternallyVisibleInterface의 이름을 언급 할 필요조차 없습니다.

    0

    개발자가 개발 환경을 갖자 마자 그는 거의 모든 것을 할 수 있으며이를 제어하려고 시도해서는 안됩니다.당신이 할 수있는 가장 핵심 응용 프로그램과 확장 DLL 사이의 한계를 확인하고 개체를 그 DLL을 에서 수신하도록하는 것입니다 이럴

    또는 올바른 클래스를하고, 그렇지 않은 경우 독특한 메시지와 함께 중단. RTTI와 typeid를 사용

    은 일반적으로 그것은 일반적으로 나쁜 OOP 디자인의 부호이기 때문에 눈살을 찌푸리게된다 정상 사용하는 경우, 가상 방법은 적절한 코드가 호출이 충분하다 전화. 하지만 유스 케이스에서는 안전하게 고려할 수 있다고 생각합니다.