我目前正在开发一个基于小部件的图形用户界面。它的结构是一个树,widget作为叶子,容器作为树的节点。这种结构的(可解决的)问题是,widget类接受对其父容器的引用。然而,这使得容器类不可能访问widget类的受保护成员(这里的"draw"成员造成了麻烦)。
下面是导致问题的核心代码。当然,这可以通过将成员公开化来解决。然而,那不是我想要的风格。
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;
}
这是Visual Studio 2008给我的输出,当我试图编译我的代码:
1>------ Build started: Project: ClassesTest, Configuration: Debug Win32 ------
1>Compiling...
1>ClassesTest.cpp
1>e:visual studio 2008projectsclassestestclassestestclassestest.cpp(26) : error C2248: 'Widget::draw' : cannot access protected member declared in class 'Widget'
1> e:visual studio 2008projectsclassestestclassestestclassestest.h(14) : see declaration of 'Widget::draw'
1> e:visual studio 2008projectsclassestestclassestestclassestest.h(6) : see declaration of 'Widget'
1>Build log was saved at "file://e:Visual Studio 2008ProjectsClassesTestClassesTestDebugBuildLog.htm"
1>ClassesTest - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
任何建议都将非常感谢!
菲利普
你的代码基本上等于这个,关于你的具体问题:
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
的受保护成员。访问权限的工作方式如下:
-
Derived
可以不访问Base
的受保护的东西,如果Base
是不同的实例。 -
Derived
可以在自己的实例中访问Base
的受保护内容。 -
Derived
可以访问另一个Derived
的私有内容。
解决问题的最快方法可能是让Container::draw()
成为Widget
的朋友。