Question

I am currently working on a widget-based graphical user interface. It is structured as a tree with Widgets as the leaves and Containers as the nodes of the tree. The (solvable) problem with this structure is that the Widget-class takes a reference to the Container that is its parent. However, this makes it impossible for the Container class to access the protected members of the Widget-class (here the "draw" member is causing trouble).

Here is the core of the code causing the problem. Of course this can be solved by making the members public. However, that is not the style that I would like.

ClassesTest.h:

class Container;

class Widget {
public:
    Widget(Container *parent);
    virtual ~Widget();

protected:
    Container *parent;

    virtual void draw();
};

class Container : public Widget {
public:
    Container(Container *parent);
    virtual ~Container();

protected:
    std::list<Widget *> childs;

private:
    friend Widget::Widget(Container *);
    friend Widget::~Widget();

    virtual void draw();

    void addChild(Widget *child);
    void removeChild(Widget *child);
};

ClassesTest.cpp

#include "stdafx.h"
#include "ClassesTest.h"

Widget::Widget(Container *parent) {
    this->parent = parent;
    parent->addChild(this);
}

Widget::~Widget() {
    parent->removeChild(this);
}

void Widget::draw() {
    //Draw the leaf
}


Container::Container(Container *parent) : Widget(parent) {}

Container::~Container() {}

void Container::draw() {
    //Draw all the childs

    for (std::list<Widget *>::iterator i = childs.begin(); i != childs.end(); i++) {
        (*i)->draw();
    }
}

void Container::addChild(Widget *child) {
    childs.push_back(child);
}

void Container::removeChild(Widget *child) {
    childs.remove(child);
}


int main(int argc, char* argv[])
{
    //Do something useful!
    return 0;
}

And this is the output Visual Studio 2008 gives me when I am trying to compile my code:

1>------ Build started: Project: ClassesTest, Configuration: Debug Win32 ------
1>Compiling...
1>ClassesTest.cpp
1>e:\visual studio 2008\projects\classestest\classestest\classestest.cpp(26) : error C2248: 'Widget::draw' : cannot access protected member declared in class 'Widget'
1>        e:\visual studio 2008\projects\classestest\classestest\classestest.h(14) : see declaration of 'Widget::draw'
1>        e:\visual studio 2008\projects\classestest\classestest\classestest.h(6) : see declaration of 'Widget'
1>Build log was saved at "file://e:\Visual Studio 2008\Projects\ClassesTest\ClassesTest\Debug\BuildLog.htm"
1>ClassesTest - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Any suggestions would be appreciated!

Filip

Was it helpful?

Solution

Your code is essentially equal to this, with regard to your specific problem:

class Base
{
protected:
    virtual void f() {}
};

class Derived : public Base
{
    void h()
    {
        Base().f();    // no can do - Base() creates another instance.
        f();           // sure, why not. it's the same instance, go ahead.
        Derived().f(); // sure, why not. it's the same type, go ahead.
    }
};

The problem is that although Derived inherits from Base, it still doesn't have access to Base's protected members. The way access rights works here is as follows:

  1. Derived can not access Base's protected stuff if Base is a different instance.
  2. Derived can access Base's protected stuff in it's own instance.
  3. Derived can access another Derived's private stuff.

The quickest way to solve your problem would probably make Container::draw() a friend of Widget.

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