如果我们有钻石继承并使用公共虚拟基类,我们可以阻止多次调用第一个构造函数。现在,我想对构造函数之外的函数做同样的事情。例如,代码:
#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
什么样的策略或模式可以实现这一目标?
我比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的函数进行计算。这似乎有点冗长,所以也许有更好的方法来做到这一点。
再次感谢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类中,因此我们可以访问受保护的成员。
答案 0 :(得分:3)
只是polkadotcadaver的想法的实现。这里,Limiter
被设计为可重用的机制,虚拟基类应该具有该类型的成员。受控的基类函数使用bool Limiter::do_next()
来询问它是否应该“像往常一样”运行或立即返回,而调用基类函数的派生类从限制器获取范围保护对象,如果不是已经声明,并释放它在销毁时的所有权。
#include <iostream>
class Limiter
{
public:
Limiter() : state_(Unlimited) { }
class Scope
{
public:
Scope(Limiter& l)
: p_(l.state_ == Unlimited ? &l : NULL)
{ if (p_) p_->state_ = Do_Next; }
~Scope() { if (p_) p_->state_ = Unlimited; }
private:
Limiter* p_;
};
Scope get() { return Scope(*this); }
bool do_next()
{
if (state_ == Do_Next) { state_ = Suspended; return true; }
return state_ != Suspended;
}
private:
enum State { Unlimited, Do_Next, Suspended } state_;
};
struct A {
Limiter limiter_;
virtual void foo() {
if (limiter_.do_next())
std::cout << "A" << std::endl;
}
};
struct B : virtual public A {
virtual void foo() {
Limiter::Scope ls = A::limiter_.get();
A::foo();
std::cout << "B" << std::endl;
}
};
struct C : virtual public A {
virtual void foo() {
Limiter::Scope ls = A::limiter_.get();
A::foo();
std::cout << "C" << std::endl;
}
};
struct D : public B, public C{
virtual void foo() {
Limiter::Scope ls = A::limiter_.get();
B::foo();
C::foo();
std::cout << "D" << std::endl;
}
};
int main() {
D d;
d.foo();
}
花了一些时间来弄清楚你在代码中做了些什么;-P - 所以为了讨论起见,我会发布我把它归结为:
#include <iostream>
namespace foo {
struct A {
A() { std::cout << "A\n"; }
};
struct B : virtual public A {
B() { std::cout << "B\n"; }
};
struct C : virtual public A {
C() { std::cout << "C\n"; }
};
struct D : public B, public C{
D() { std::cout << "D\n"; }
};
}
struct A { virtual void foo() { foo::A(); } };
struct B : virtual public A { void foo() { foo::B(); } };
struct C : virtual public A { void foo() { foo::C(); } };
struct D : public B, public C { void foo() { foo::D(); } };
int main() {
D d;
d.foo();
}
为了他人的缘故 - 这可以让A..D::foo()
函数创建类型为foo::A..D
的临时对象,其构造函数为virtual
基本名称,foo::A::A()
为foo::
只召唤一次。
作为一般解决方案,问题在于您必须手动同步{{1}}结构,因此存在冗余和脆弱性。虽然很聪明!