3

I have a class that has some data members that I want to be hidden from the caller (because including the headers for their types significantly increases the compile time, and it would require every project using this class to add an additional path to their include paths).

This class uses QSharedDataPointer to store this data. This way it can be copied by using the default copy constructor.

The basic structure of this class is:

class MyClass {
private:
  QSharedDataPointer<MySharedClassData> m_data;
};

Is there any fancy trick to do this without defining MySharedClassData (which inherits from QSharedData) in the same header file? Or is there any other good way of hiding data fields?

I've already tried a forward declaration of MySharedClassData but this didn't work (despite the fact that m_data is private).

The only solution I can currently thing of is to declare m_data as QSharedDataPointer<QSharedData> but then I need to cast the data member every time I want to access it. Is there a better solution?

demonplus
  • 5,613
  • 12
  • 49
  • 68
Sebastian Krysmanski
  • 8,114
  • 10
  • 49
  • 91
  • 1
    Is [Pimpl](http://en.wikipedia.org/wiki/Opaque_pointer) idiom a thing I can think of in this case? – maverik Feb 07 '12 at 12:27
  • @maverik: Yes. "The `QSharedDataPointer` class represents a `p`ointer to an `impl`icitly shared object." – MSalters Feb 07 '12 at 12:35
  • Yes, this is exactly what I'm trying to do. Unfortunately this doesn't seem to work with `QSharedDataPointer`. Or at least I can't figure out, how to do this. – Sebastian Krysmanski Feb 07 '12 at 12:35

3 Answers3

6

The forward declaration should be working as long as you constructor and destructor are not defined in the header. The following class compiles on my computer:

#ifndef MAIN_WINDOW_HXX
#define MAIN_WINDOW_HXX

#include <QMainWindow>
#include <ui_MainWindow.h>

#include <QSharedDataPointer>

class MySharedClassData;

class MainWindow : public QMainWindow, private Ui_MainWindow {
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
    virtual ~MainWindow();

    QSharedDataPointer<MySharedClassData> m_data;

};

#endif

If you try to inline your constructor/destructor, then you might receive a: C2027: use of undefined type 'type' under VS.

tibur
  • 11,531
  • 2
  • 37
  • 39
0

Yes. There's no really fancy trick required. However, all methods that do need MySharedClassData must be defined after the definition of MySharedClassData. If you move the class definition to a .cpp file, the methods have to be moved there too.

MSalters
  • 173,980
  • 10
  • 155
  • 350
0

In general, if you want to use the pimpl idiom with a smart pointer to a forward-declared impl (rather than managing the impl object manually), you need a smart pointer with an out-of-line deleter, like boost::shared_ptr (you should be able to use std::unique_ptr with a custom deleter, but I haven't tried).

The requirement is that you can instantiate the smart pointer template without seeing the impl class destructor: this rules out std::auto_ptr for example.

I don't know whether QSharedDataPointer meets the requirement or not, but tibur seems to say it does.

Useless
  • 64,155
  • 6
  • 88
  • 132