c++classopencvc++11forward-declaration

Forward Declaration (PIMPL) for External Libraries also used in Method Declarations?


I have looked at a significant number of posts regarding forward declarations/PIMPL, but haven't quite managed to get it to work with the external libraries I'm using. I want to create a shared library where the client does not need to include the external library headers.

This is what I currently have.

################
## myClass.h ##
################

#include <opencv2/opencv.hpp> ------> I want this header in the implementation file instead.

class A;
class B;
class C;

class __declspec(dllexport) myClass
{
public:
    myClass();
    ~myClass();
    cv::Mat myFunction(cv::Mat &img);
private:
    A *_a;
    B *_b;
    C *_c;
};

################
## myClass.cpp ##
################

#include "myClass.h"
#include "a.h"
#include "b.h"
#include "c.h"

myClass::myClass()
{
    _a = new A;
    _b = new B;
    _c = new C;
}

myClass::~myClass()
{
    delete _a;
    delete _b;
    delete _c;
}

cv::Mat myClass::myFunction(cv::Mat &img){ ... }

################
## a.h ##
################

class A
{
public:
    A();
    ... -----> A's methods
};

################
## b.h ##
################

class B{ ... };

################

################
## c.h ##
################

class C{ ... };

################

Here's what I have tried (updated to show PIMPL)

################
## myClass.h ##
################

/*
namespace cv{
    class Mat; ------> Forward declaration of cv::Mat
}
*/

class __declspec(dllexport) myClass
{
public:
    myClass();
    ~myClass();
    //cv::Mat myFunction(cv::Mat &img); ------> Get an error since I'm declaring an incomplete type cv::Mat.
private:
    class A;
    class B;
    class C;
    A *_a; --------------> PIMPL
    B *_b;
    C *_c;
    //std::unique_ptr<cv::Mat> _m; ---------> PIMPL
};

################
## myClass.cpp ##
################

#include "myClass.h"
#include "a.h"
#include "b.h"
#include "c.h"
#include <opencv2/opencv.hpp>

myClass::myClass()
{
    _a = new A();
    _b = new B();
    _c = new C();
}

myClass::~myClass()
{
    delete _a;
    delete _b;
    delete _c;
}

################
## a.h ##
################

#include "myClass.h"

class myClass::A
{
public:
    A();
    ... -----> A's methods
};

Any assistance or guidance would be appreciated. Thanks


Solution

  • The part of the interface of your library is a function, that accepts an argument of type cv::Mat and returns cv::Mat by value. Suppose this simple code:

    #include <myClass.h>  // your library header
    #include <opencv2/opencv.hpp>  // OpenCV header
    
    int main() {
      myClass o;
      cv::Mat input;
      cv::Mat result = o.myFunction(input);
    }
    

    I want to create a shared library where the client does not need to include the external library headers.

    How could a user write such code without including some OpenCV header where the cv::Mat class is defined? This is simply not possible.

    Even if you redeclared/redefined myFunction to:

    cv::Mat* myFunction(cv::Mat* img); 
    

    then, the user would still need to include OpenCV headers in their code to be able to create an input object pointed to by the function argument and work with the returned pointed-to output object.

    The only possibility I can think of would be to wrap cv::Mat completely with your own library type and use it in your interface instead of cv::Mat. But then, users would need to use this type instead something well-known. Which would be very bad design in my opinion.


    BTW, you mentioned PIMPL. But PIMPL is about something else. It's about hiding implementation details. Here, cv::Mat is a part of your library interface. You cannot hide interface, because then it wouldn't be interface any more.