2013-07-09 2 views
3

У меня есть класс, на котором я хотел бы использовать шаблон построителя, но он получен из базового класса, атрибуты которого мне нужно получить. Я не могу получить доступ к членам BaseClass в моей реализации, не делая их общедоступными, даже если я получаю Builder от BaseClass или что-то столь же вонючее. Мои классы:C++ Builder Pattern with Inheritance

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 
} 

Моя проблема заключается в том, что я не могу получить доступ к builder.name , Visual Studio говорит, что «защищенный член BaseClass::name недоступен указателю или объекту DerivedClass::Builder». Я пробовал играть с Builder a friend из BaseClass, но безрезультатно. Этот post также предоставил обходной путь, но он для Java и очень грязный.

Есть ли достойный способ использования шаблона-строителя с наследованием на C++?

ответ

3

Даже если Builder объявлен внутри DerivedClass, Builder не неявно дружит с DerivedClass, как вы ожидаете. Builder по-прежнему является его собственным классом, и он следует тем же правилам, что и любой другой класс, включая правила доступа к областям. Вот почему DerivedClass не может получить доступ к protected членам Builder по умолчанию. Вам нужно явно объявить эту дружбу.

Кроме того, ваш метод Builder::Description() не будет работать как есть, потому что Builder не имеет члена description. Указатель внутри методов Builder по-прежнему ссылается на экземпляр Builder, а не на экземпляр DerivedClass. Если вы хотите, чтобы Builder обращался к членам DerivedClass, ему должен быть указатель на экземпляр DerivedClass. В противном случае дайте Builder свой собственный член description (который, похоже, вы все равно пытались сделать).

Попробуйте это:

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 
} 
+0

Это похоже на то, что я искал, спасибо! – aguazales

+0

Правила доступа были обновлены на C++ 11. Вложенный класс теперь имеет доступ ко всем именам, к которым может обращаться доступный класс (см. [This] (http://en.cppreference.com/w/cpp/language/nested_types)). – Excambion

2

Не пытайтесь получить доступ к элементу напрямую. Используйте общедоступный метод доступа.

+0

Но если член только ' protected ', не должен ли я иметь доступ к нему напрямую потому что мой «Builder» получен из «BaseClass», в котором хранится элемент? – aguazales

+0

Думаю, я просто хотел бы знать, почему у меня есть доступ к члену, который отлично подходит в файле заголовка, но не в файле cpp. – aguazales