Search code examples
c++oopc++11design-patternsbuilder

C++ Builder Pattern with Forward Declaration


I recently got stuck in a situation. In the first version, everything is implemented in header file and it works fine. In the second version when i tried to separate implementation from header declarations, I got many errors. In the below lines, i m going to demonstrate problem. Thanks in advance..

First Version (it works fine!)

cameravalue.h

#ifndef CAMERAVALUE_H
#define CAMERAVALUE_H
#include <string>



class CameraValue
{
private:

  class CameraProperties
  {
  private:
    CameraProperties()
      : mId(-1),
        mName(),
        mAddress(),
        mExposure(),
        mFocus()
    {}

    int mId;
    std::string mName;
    std::string mAddress;
    std::string mExposure;
    long long  mFocus;

    friend class CameraValue;
    friend class CameraBuilder;
  };

public:
  class CameraBuilder
  {
  public:
    CameraBuilder(int id)
    {
      mProperties.mId = id;
    }

    CameraBuilder& setName(std::string& name)
    {
      mProperties.mName = name;
      return *this;
    }

    CameraBuilder& setAddress(std::string& adress)
    {
      mProperties.mAddress = adress;
      return *this;
    }

    CameraBuilder& setExposure(std::string& exposure)
    {
      mProperties.mExposure = exposure;
      return *this;
    }

    CameraBuilder& setFocus(int focus)
    {
      mProperties.mFocus = focus;
      return *this;
    }

    CameraValue build()
    {
      return CameraValue(mProperties);
    }

  private:
    CameraProperties mProperties;
  };

private:
  CameraValue(const CameraProperties& properties)
    :mProperties(properties)
    {}

  CameraProperties mProperties;
};

#endif // CAMERAVALUE_H

main.cpp

#include "cameravalue.h"
#include <iostream>

int main(int argc, char *argv[])
{

  CameraValue cm = CameraValue::CameraBuilder(1).setName(std::string("Huseyin")).build();
  return 0;
}

Second Version (Don't work)

cameravalue.h

#ifndef CAMERAVALUE_H
#define CAMERAVALUE_H
#include <string>



class CameraValue
{
private:

  class CameraProperties;

public:

  class CameraBuilder;

private:
  CameraValue(const CameraProperties& properties);

  CameraProperties mProperties;
};

#endif // CAMERAVALUE_H

cameravalue.cpp

#include "cameravalue.h"
#include <string>



class CameraValue::CameraProperties
{
private:
  CameraProperties()
    : mId(-1),
      mName(),
      mAddress(),
      mExposure(),
      mFocus()
  {}

  int mId;
  std::string mName;
  std::string mAddress;
  std::string mExposure;
  long long  mFocus;

  friend class CameraValue;
  friend class CameraBuilder;
};



class CameraValue::CameraBuilder
{
public:
  CameraBuilder(int id)
  {
    mProperties.mId = id;
  }

  CameraBuilder& setName(std::string& name)
  {
    mProperties.mName = name;
    return *this;
  }

  CameraBuilder& setAddress(std::string& adress)
  {
    mProperties.mAddress = adress;
    return *this;
  }

  CameraBuilder& setExposure(std::string& exposure)
  {
    mProperties.mExposure = exposure;
    return *this;
  }

  CameraBuilder& setFocus(int focus)
  {
    mProperties.mFocus = focus;
    return *this;
  }

  CameraValue build()
  {
    return CameraValue(mProperties);
  }

private:
  CameraProperties mProperties;
};



CameraValue::CameraValue(const CameraProperties& properties)
  : mProperties(properties)
  {}

main.cpp

#include "cameravalue.h"
#include <iostream>

int main(int argc, char *argv[])
{

  CameraValue cm = CameraValue::CameraBuilder(1).setName(std::string("Huseyin")).build();
  return 0;
}

Compile Errors

cameravalue.cpp
c:\users\huseyin\documents\builderpattern\cameravalue.h(20) : error
C2079: 'CameraValue::mProperties' uses undefined class
'CameraValue::CameraProperties' ..\BuilderPattern\cameravalue.cpp(74)
: error C2440: 'initializing' : cannot convert from 'const
CameraValue::CameraProperties' to 'int'
        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
..\BuilderPattern\cameravalue.cpp(74) : error C2439:
'CameraValue::mProperties' : member could not be initialized
        c:\users\huseyin\documents\builderpattern\cameravalue.h(20) : see declaration of 'CameraValue::mProperties'
c:\users\huseyin\documents\builderpattern\cameravalue.h(20) : error
C2079: 'CameraValue::mProperties' uses undefined class
'CameraValue::CameraProperties' ..\BuilderPattern\main.cpp(9) : error
C2440: '<function-style-cast>' : cannot convert from 'int' to
'CameraValue::CameraBuilder'
        Source or target has incomplete type ..\BuilderPattern\main.cpp(9) : error C2228: left of '.setName' must
have class/struct/union ..\BuilderPattern\main.cpp(9) : error C2228:
left of '.build' must have class/struct/union
..\BuilderPattern\main.cpp(9) : error C2512: 'CameraValue' : no
appropriate default constructor available
..\BuilderPattern\main.cpp(10) : error C2039: 'getName' : is not a
member of 'CameraValue'
        c:\users\huseyin\documents\builderpattern\cameravalue.h(8) : see declaration of 'CameraValue'

Solution

  • Definition of class CameraBuilder should be visible in main.cpp, so you can't just forward-declare it in cameravalue.h. But you can make the definitions of its member functions out-of-line:

    // cameravalue.h
    class CameraValue {
        class CameraBuilder {
        public:
            CameraBuilder(int id);
            ...
        };
    };
    
    // cameravalue.cpp
    CameraValue::CameraBuilder::CameraBuilder(int id) {
        ...
    }