2017-08-13 101 views
0

我了解C++类的多态性的方式,它允许以相同的方式处理类及其子类。因此,如果我有一个类及其子类的多个对象,并将它们存储在基类的(智能)指针向量中,则可以调用它们上的任何虚拟方法,它将工作得很好。如何在处理基类的多重指针时同时处理多态性?

class Dancer { 
public: 
    virtual void f() const { std::cout << "I am a basic dancer" << std::endl; } 
}; 

class SkilledDancer : public Dancer { 
public: 
    void f() const { std::cout << "I am a skilled dancer" << std::endl; } 
}; 

int main(int argc, char *argv[]) 
{ 
    std::vector< std::shared_ptr<Dancer> > dancers; 
    dancers.push_back(std::make_shared<Dancer>(Dancer())); 
    dancers.push_back(std::dynamic_pointer_cast<Dancer>(std::make_shared<SkilledDancer>(SkilledDancer()))); 

    for(auto & dancer : dancers){ 
     dancer->f(); //works fine 
    } 
} 

但现在我有一个问题,当我想这种行为,使用运营商或与两个对象处理方法时。如果一个函数需要输入基类的两个参数,我该如何考虑它们实际上可能是派生类的对象的事实?

class Dancer { 
public: 
    virtual void g(const Dancer & d) const { std::cout << "Let's do a basic dance" << std::endl; } 
}; 

class SkilledDancer : public Dancer { 
public: 

    //what should I do here ? 

    void g(const Dancer & d) const { std::cout << "Let's do an advanced dance" << std::endl; } 
    //would overload Dancer::g but wrong because d is only a Dancer 

    void g(const SkilledDancer & d) { std::cout << "Let's do an advanced dance" << std::endl; } 
    //doest not overload Dancer::g because different signature 
    //so would never be called if dealing with two smart pointers of the base class 
}; 

int main(int argc, char *argv[]) 
{ 
    auto basic = std::make_shared<Dancer>(Dancer()); 
    auto advanced = std::dynamic_pointer_cast<Dancer>(std::make_shared<SkilledDancer>(SkilledDancer())); 
    basic->g(*advanced); //OK 
    advanced->g(*advanced); //seems good ... 
    advanced->g(*basic); //... but wrong 
} 

我设法找到一个解决方法(下面的代码),但它需要派生类的一个其他成员,另外两个函数调用,该函数不能是const了。所以我想知道是否有更好的方法来处理这个问题。

如果我面临XY问题,我的实际问题是关于矩阵。我希望有一个矩阵算子乘以矩阵,但是当处理两个特定的矩阵(如三角形或对称矩阵类的子类)时,我想调用另一个算子。请注意,所有类型的矩阵都存储为矩阵基类的指针。

class Dancer { 
public: 
    virtual void g(const std::shared_ptr<Dancer> & d) { std::cout << "Let's do a basic dance" << std::endl; } 
}; 

class SkilledDancer : public Dancer { 
public: 
    SkilledDancer() : dummy_g(false) {} 
    bool dummy_g; 

    void g(const std::shared_ptr<Dancer> & d) { 
     if(!dummy_g){ 
      dummy_g = true; 
      d->g(std::dynamic_pointer_cast<Dancer>(std::make_shared<SkilledDancer>(*this))); 
     } else { 
      dummy_g = false; 
      ((SkilledDancer*)d.get())->dummy_g = false; 
      std::cout << "Let's do an advanced dance" << std::endl; 
     }  
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    //all cases work fine 
    basic->g(basic); 
    advanced->g(advanced); 
    basic->g(advanced); 
    advanced->g(basic); 
} 
+2

查找双倍/多次调度。 –

+1

[OT]:您应该从'std :: make_shared (Dancer())'' – Jarod42

+0

'中移除'Dancer()'谢谢你告诉我背后的概念的名字。因此,如果我理解正确,那么在C++中就不存在对多次调度的本地支持(维基百科文章提到访客模式的动态转换,但它们似乎不是很好的选择)。 好评的make_shared评论! – yultan

回答

1

这就是你刚刚试图用你的“舞者”的例子吗?

class Dancer 
{ 
public: 
    virtual void danceWith(Dancer * dancer) { 
     std::cout << "Let's do a basic dance" << std::endl; 
    } 
}; 

class SkilledDancer : public Dancer 
{ 
public: 
    void danceWith(Dancer * dancer) override 
    { 
     if(auto skilledDancer = dynamic_cast< SkilledDancer*>(dancer)) { 
      danceWith(skilledDancer); 
     } else { 
      Dancer::danceWith(dancer); 
     } 
    } 

    void danceWith(SkilledDancer * dancer) { 
     std::cout << "Let's do an advanced dance" << std::endl; 
    } 
}; 

后来:

Dancer* basic = new Dancer; 
SkilledDancer* advanced = new SkilledDancer; 
Dancer* pretending = advanced; 

basic ->danceWith(basic);   // -> Let's do a basic dance 
advanced->danceWith(advanced);  // -> Let's do an advanced dance 
basic ->danceWith(advanced);  // -> Let's do a basic dance 
advanced->danceWith(basic);   // -> Let's do a basic dance 
advanced->danceWith(pretending); // -> Let's do an advanced dance 

基本上,我们只使用该编译器总是选择的函数重载在参数方面拟合大部分事实。在SkilledDancer类中:对于所有SkilledDancer*类型参数,将调用danceWith()的第二个重载(并且它在编译时决定 - 没有多态转换开销)。同时,所有Dancer*类型的参数都需要运行时检查,并且调用覆盖的danceWith()。执行检查并选择要呼叫的相应版本danceWith()。如果舞者基本 - 跳舞基本,如果他只是假装 - 舞蹈先进。