Question

I have a class I would like to use the builder pattern on, but it is derived from a base class whose attributes I need to access. I can't access the members of BaseClass in my implementation without making them public, even if I derive Builder from BaseClass or something equally smelly. My classes:

BaseClass.h:

class BaseClass
{
    protected:
        CString name;
}

DerivedClass.h:

class DerivedClass : public BaseClass
{
    public:
        // builder starts here and has the same base class as the class it is nested in
        // (if it doesn't, we can't get access to name)
        static class Builder : public BaseClass
        {
            public:

                Builder::Builder(CString pName)
                {
                    this->name = pName;
                }

                Builder Builder::Description(CString pDescription)
                {
                    this->description = pDescription;
                    return *this;
                }
        };

    public:
        CString description;
};

DerivedClass.cpp:

DerivedClass::DerivedClass(Builder builder)
{
    this->name = builder.name; // this is NOT ok
    this->description = builder.description; // this is ok
}

My problem is that I can't access builder.name. Visual Studio says that "protected member BaseClass::name is not accessible through a DerivedClass::Builder pointer or object". I've tried fiddling around with making Builder a friend of BaseClass, but to no avail. This post has also provided a workaround, but it's for Java, and very messy.

Is there a decent way to use the builder pattern with inheritance in C++?

Was it helpful?

Solution

Even though Builder is declared inside of DerivedClass, Builder is not implicitly friends with DerivedClass, like you are expecting. Builder is still its own class, and it follows the same rules as any other class, including scope access rules. That is why DerivedClass cannot access protected members of Builder by default. You need to explicitly declare that friendship.

Also, your Builder::Description() method will not work as-is because Builder does not have a description member. The this pointer inside of Builder methods still refers to the Builder instance, not a DerivedClass instance. If you want the Builder to access members of DerivedClass, it needs to be given a pointer to a DerivedClass instance. Otherwise, give Builder its own description member (which it looks like you were attempting to do anyway).

Try this:

BaseClass.h:

class BaseClass
{
protected:
    CString name;
};

DerivedClass.h:

class DerivedClass : public BaseClass
{
public:
    class Builder : public BaseClass
    {
    public:
        Builder(const CString &pName)
        {
            this->name = pName;
        }

        Builder& Description(const CString &pDescription)
        {
            this->description = pDescription;
            return *this;
        }

    public:
        CString description; // <-- add this

    friend class DerivedClass; // <-- add this
    };

public:
    DerivedClass(const Builder &builder);

public:
    CString description;
};

DerivedClass.cpp:

DerivedClass::DerivedClass(const DerivedClass::Builder &builder)
{
    this->name = builder.name; // this is ok now
    this->description = builder.description; // this is ok now
}

OTHER TIPS

Don't attempt to access the member directly. Use a public accessor method.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top