2015-04-21 18 views
5

Dinamik bir gönderimden kaçınan bir sanal işlevle üye işlev işaretçisi istediğim bir durum var. Aşağıya bakın: Merak edenler içinÜye işlev işaretçisi aracılığıyla temel işlev çağrısı işlevini sanal işlevle çağırma

struct Base 
{ 
    virtual int Foo() { return -1; } 
}; 

struct Derived : public Base 
{ 
    virtual int Foo() { return -2; } 
}; 

int main() 
{ 
    Base *x = new Derived; 

    // Dynamic dispatch goes to most derived class' implementation  
    std::cout << x->Foo() << std::endl;  // Outputs -2 

    // Or I can force calling of the base-class implementation: 
    std::cout << x->Base::Foo() << std::endl; // Outputs -1 

    // Through a Base function pointer, I also get dynamic dispatch 
    // (which ordinarily I would want) 
    int (Base::*fooPtr)() = &Base::Foo; 
    std::cout << (x->*fooPtr)() << std::endl; // Outputs -2 

    // Can I force the calling of the base-class implementation 
    // through a member function pointer? 
    // ...magic foo here...? 

    return 0; 
} 

, ben türetilmiş sınıf uygulaması memoize için bir yardımcı sınıfını kullanarak bunun nedeni istiyorum nedeni taban sınıfta kullanıma (etrafında bir önbellek ekleyin). Hizmet sınıfı bir işlev işaretçisi alır, ancak, elbette, işlev işaretçisi en türetilmiş sınıfa dinamik olarak gönderir ve sonsuz bir yineleme elde ederim.

x->Base::foo() ile elde ettiğim statik gönderme davranışını yeniden üretmeme izin veren bir sözdizimi var mı, yoksa bir işlev işaretçisi mi?

cevap

1

Böyle Base* dilimleme zorlayacağını:

std::cout << (static_cast<Base>(*x).*fooPtr)() << std::endl; // Outputs -1 
+0

ilginç ... ama bu aslında Bas çağırır e kopya kurucu böylece sadece bazı durumlarda uygulanabilir. Base'in özel bir kopya kurucusu veya herhangi bir sanal işlevi varsa, bu çözüm geçerli olmaz. – SimonD

0

istediğiniz mülkün hiçbir ayaklı "üye işlev işaretçisi" var. sınıf Base özel, tek seferlik kullanım senaryosunu ve sizin kontrolünüz altında ise

Base * x = new Derived; 
auto f = [x]() { x->Base::Foo(); } 
f(); 

, muhtemelen "ziyaretçi kabul" çeşit eklemek gerekir: Ciltli üye işlevine yakın şey bir kapaktır buna fonksiyon böylece vb x->accept(foo_caller); C++ 14'te örneği gibi, dinamik olarak üye arayanlar içinde geçirebilirsiniz:

struct X 
{ 
    template <typename F> 
    auto accept(F && f) 
    { 
     return [this, &f](auto &&... args) { 
      return f(this, std::forward<decltype(args)>(args)...); }; 
    } 

    virtual void foo() const { std::cout << "base\n"; } 
}; 

Kullanımı:

void call_static_foo(X * p) 
{ 
    p->accept([](X * that){that->X::foo();}); 
} 
+0

[Demo] (http://ideone.com/h4QXUi). –

+0

Bir lambda'nın nasıl yardımcı olacağını hayal edebiliyorum ama 'kabul etmenin' amacını anlamıyorum ...? Ayrıca demo baskı 'türetilmiş', 'base' isterken ... bir şey özlüyor muyum? – SimonD

+0

Demoda, döndürülmesi gereken döndürme birimi: 'p-> kabul et ([] (X * bu) {that-> X :: foo();})();' Tabanı beklendiği gibi yazdırır. Yine de kabul edildikten nasıl bir avantaj elde edildiğini bilmiyor musunuz? – SimonD

İlgili konular