Проблемы с вложенным наследованием в Visual Studio 2008

В настоящее время я работаю над графическим пользовательским интерфейсом на основе виджетов. Он структурирован как дерево с виджетами в качестве листьев и контейнерами в качестве узлов дерева. (Решаемая) проблема с этой структурой заключается в том, что класс Widget берет ссылку на контейнер, который является его родителем. Однако это делает невозможным для класса Container доступ к защищенным членам класса Widget (здесь член «draw» вызывает проблемы).

Вот ядро ​​кода, вызывающего проблему. Конечно, это можно решить, сделав членов общедоступными. Однако это не тот стиль, который мне бы хотелось.

КлассыTest.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);
};

КлассыTest.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;
}

И это вывод Visual Studio 2008, когда я пытаюсь скомпилировать свой код:

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 ==========

Мы ценим любые предложения!

Филип


person Filip    schedule 01.10.2011    source источник


Ответы (1)


Ваш код по существу равен этому, что касается вашей конкретной проблемы:

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.
    }
};

Проблема в том, что хотя Derived наследуется от Base, он по-прежнему не имеет доступа к защищенным членам Base. Принцип работы прав доступа здесь следующий:

  1. Derived не может не получить доступ к защищенным материалам Base, если Base является другим экземпляром.
  2. Derived может получить доступ к защищенным материалам Base в своем собственном экземпляре.
  3. Derived может получить доступ к личным данным другого Derived.

Самый быстрый способ решить вашу проблему, вероятно, сделать Container::draw() другом Widget.

person eran    schedule 01.10.2011