【发布时间】:2014-01-05 23:57:20
【问题描述】:
如果我们有菱形继承并使用公共虚拟基类,我们可以阻止第一个构造函数被多次调用。现在,我想对构造函数之外的函数做同样的事情。例如代码:
#include <iostream>
struct A {
virtual void foo() {
std::cout << "A" << std::endl;
}
};
struct B : virtual public A {
virtual void foo() {
A::foo();
std::cout << "B" << std::endl;
}
};
struct C : virtual public A {
virtual void foo() {
A::foo();
std::cout << "C" << std::endl;
}
};
struct D : public B, public C{
virtual void foo() {
B::foo();
C::foo();
std::cout << "D" << std::endl;
}
};
int main() {
D d;
d.foo();
}
产生结果
A
B
A
C
D
我想修改它,让它只产生
A
B
C
D
什么样的策略或模式可以做到这一点?
编辑 1
我更喜欢 Tony D 的回答,而不是下面的回答。尽管如此,理论上可以使用另一个类的构造函数来定义函数的适当层次结构。具体
#include <iostream>
struct A;
struct B;
struct C;
struct D;
namespace foo {
struct A {
A(::A* self);
};
struct B : virtual public A {
B(::B* self);
};
struct C : virtual public A {
C(::C* self);
};
struct D : public B, public C{
D(::D* self);
};
}
struct A {
private:
friend class foo::A;
friend class foo::B;
friend class foo::C;
friend class foo::D;
int data;
public:
A() : data(0) {}
virtual void foo() {
(foo::A(this));
}
void printme() {
std::cout << data << std::endl;
}
};
struct B : virtual public A {
virtual void foo() {
(foo::B(this));
}
};
struct C : virtual public A {
virtual void foo() {
(foo::C(this));
}
};
struct D : public B, public C{
virtual void foo() {
(foo::D(this));
}
};
foo::A::A(::A* self) {
self->data+=1;
std::cout << "A" << std::endl;
}
foo::B::B(::B* self) : A(self) {
self->data+=2;
std::cout << "B" << std::endl;
}
foo::C::C(::C* self) : A(self) {
self->data+=4;
std::cout << "C" << std::endl;
}
foo::D::D(::D* self) : A(self), B(self), C(self) {
self->data+=8;
std::cout << "D" << std::endl;
}
int main() {
D d;
d.foo();
d.printme();
}
基本上,命名空间 foo 中的类为名为 foo 的函数进行计算。这似乎有点冗长,所以也许有更好的方法。
编辑 2
再次感谢 Tony D 澄清上述示例。是的,基本上上面所做的就是创建符合虚拟基础名称的临时变量。这样,我们可以使用构造函数来防止冗余计算。额外的麻烦是尝试并展示如何访问可能隐藏在基类中的私有成员。再想一想,还有另一种方法可以做到这一点,根据应用程序可能会也可能不会更干净。我把它留在这里以供参考。与上一个示例一样,缺点是我们基本上需要手动再次连接继承。
#include <iostream>
struct A {
protected:
int data;
public:
A() : data(0) {}
struct foo{
foo(A & self) {
self.data+=1;
std::cout << "A" << std::endl;
}
};
void printme() {
std::cout << data << std::endl;
}
};
struct B : virtual public A {
struct foo : virtual public A::foo {
foo(B & self) : A::foo(self) {
self.data+=2;
std::cout << "B" << std::endl;
}
};
};
struct C : virtual public A {
struct foo : virtual public A::foo {
foo(C & self) : A::foo(self) {
self.data+=4;
std::cout << "C" << std::endl;
}
};
};
struct D : public B, public C{
struct foo : public B::foo, public C::foo {
foo(D & self) : A::foo(self) , B::foo(self), C::foo(self) {
self.data+=8;
std::cout << "D" << std::endl;
}
};
};
int main() {
D d;
(D::foo(d));
d.printme();
}
本质上,调用 (D::foo(d)) 会创建一个临时的构造函数来执行我们想要的操作。我们手动传入对象 d 以访问内存。由于类 foo 在 A..D 类中,因此我们可以访问受保护的成员。
【问题讨论】:
-
我能想到的就是在 A::foo() 的调用周围或内部放置一些保护变量 - 对不起!
-
除了@polkadotcadaver 的建议之外,我能想到的唯一其他方法是不要在
B和C实现中调用A::foo。不过,可能不是你想要的。
标签: c++ inheritance c++11