如何使用多态性参数动态调用函数

问题描述:

如何可以调用形式为childA.function(childB)的函数,而它们的静态类型都是父级?如何使用多态性参数动态调用函数

,并与更多的细节:

我有一个物理项目,我需要计算2个分子的潜力。我有2种类型的分子,LC和Col,每种类型都有自己的参数和东西,但是我希望能够动态地调用每种分子的潜力。

所以我尝试这样的:

#include <iostream> 
#include <typeinfo> 
#include <stdio.h> 

using namespace std; 
class Col; 
class LC; 

class Molecule 
{ 
    public: 
    /// more data and functions should be here regarding the molecule 
    double someBulshit; 
    virtual double potential(const Molecule * mol){} 
    virtual double potential(const Col * mol){} 
    virtual double potential(const LC * mol){} 
}; 

class LC : public Molecule 
{ 
    public: 
    /// more data and functions should be here regarding the LC molecule 
    virtual double potential(const Molecule * mol) {return 1;} 
    virtual double potential(const LC * mol) {return 2;} 
    virtual double potential(const Col * mol) {return 3;} 
}; 
class Col : public Molecule 
{ 
    public: 
    /// more data and function should be here regarding the Col molecule 
    virtual double potential(const Molecule * mol) {return 4;} 
    virtual double potential(const LC * mol) {return 5;} 
    virtual double potential(const Col * mol) {return 6;} 
}; 

int main(int argc, char* argv[]) 
{ 
    Molecule * mol1 = new Col(); 
    Molecule * mol2 = new LC(); 

    double my_potential = mol1->potential(mol2); 
    printf ("%f",my_potential); 
} 

,但我得到的4结果,事实证明该函数是静态调用,这意味着,由于静态类型mol1的是分子调用的函数为:

virtual double potential(const Molecule * mol) {return 4;} 

,而不是

virtual double potential(const LC * mol) {return 5;} 

反正是有调用函数DYNA mically(在OOP设计中)不使用typeid?

完整的答案:

与彼得的意见调查后,这变成是经典的双调度问题的全面解决方案只是调用另一个虚拟的虚拟里面是这样的:

#include <iostream> 
#include <typeinfo> 
#include <stdio.h> 


using namespace std; 
class Col; 
class LC; 

class Molecule 
{ 
    public: 
    /// more data and functions should be here regarding the molecule 
    double someBulshit; 
    virtual double potential(const Molecule * mol) const = 0; 
    virtual double potential(const Col * mol) const = 0; 
    virtual double potential(const LC * mol) const = 0; 
}; 

class LC : public Molecule 
{ 
    public: 
    /// more data and functions should be here regarding the LC molecule 
    virtual double potential(const Molecule * mol) const {return mol->potential(this);} 
    virtual double potential(const LC * mol) const {return 2;} 
    virtual double potential(const Col * mol) const {return 3;} 
}; 
class Col : public Molecule 
{ 
    public: 
    /// more data and function should be here regarding the Col molecule 
    virtual double potential(const Molecule * mol) const {return mol->potential(this);} 
    virtual double potential(const LC * mol) const {return 5;} 
    virtual double potential(const Col * mol) const {return 6;} 
}; 

int main(int argc, char* argv[]) 
{ 
    Molecule * mol1 = new Col(); 
    Molecule * mol2 = new LC(); 

    double my_potential = mol1->potential(mol2); 
    printf ("%f",my_potential); 
} 

并且如果需要这确实返回3。

+0

你的源代码不会编译。罪魁祸首是“分子”成员职能。您可能还想重命名“Molecule”数据成员。也许你忘了做这些纯粹的虚拟?函数不是staticly_。请提供[MCVE](https://stackoverflow.com/help/mcve)。 – Ron

+1

查看访客模式。 – Peter

您总是调用潜在的(Molecule *),因为这是您传递的参数的类型。

如果你想动态地做它(即作出一个运行时决定),你将不得不做一个动态的强制转换来决定你所拥有的类型,然后调用正确的函数。你可以例如只在基类中使用基类型参数实现该函数,检查实际类型,然后使用正确类型调用重载函数。然后,该代码看起来是这样的:

#include <iostream> 
#include <typeinfo> 
#include <stdio.h> 

using namespace std; 
class Col; 
class LC; 

class Molecule 
{ 
    public: 
    virtual ~Molecule() {} 
    /// more data and functions should be here regarding the molecule 
    double someBulshit; 
    double potential(const Molecule * mol); 
    virtual double potential(const Col * mol) = 0; 
    virtual double potential(const LC * mol) = 0; 
}; 

class LC : public Molecule 
{ 
    public: 
    virtual ~LC() {} 
    /// more data and functions should be here regarding the LC molecule 
    virtual double potential(const LC * mol) {return 2;} 
    virtual double potential(const Col * mol) {return 3;} 
}; 
class Col : public Molecule 
{ 
    public: 
    virtual ~Col() {} 
    /// more data and function should be here regarding the Col molecule 
    virtual double potential(const LC * mol) {return 5;} 
    virtual double potential(const Col * mol) {return 6;} 
}; 

double Molecule::potential(const Molecule * mol) { 
    const Col *mol_as_Col = dynamic_cast<const Col*>(mol); 
    const LC *mol_as_LC = dynamic_cast<const LC*>(mol); 
    if(mol_as_Col) { 
    return potential(mol_as_Col); 
    } 
    else if(mol_as_LC) { 
    return potential(mol_as_LC); 
    } 
    else { 
    throw; 
    } 
} 


int main(int argc, char* argv[]) 
{ 
    Molecule * mol1 = new Col(); 
    Molecule * mol2 = new LC(); 

    double my_potential = mol1->potential(mol2); 
    printf ("%f",my_potential); 
} 

其结果将是5,而不是6,你在你的问题中写道,因为你把一个类型LC,并就西电话我也开始加入失踪虚拟析构函数,因为多态类应该总是有它。

或者,您可以尝试使用模板代码实现此功能,并避免首先使用运行时多态性(即从不保持类型Molecule *的指针)。如果你有兴趣,我可以制定一个例子,但是因为你特别要求一个动态的解决方案,它似乎不是这个问题的答案。

编辑:下面是一个模板演示。没有上下文就没有意义。我添加了一个功能printPotential(),它演示了如何编写代码的其余部分:

#include <iostream> 
#include <typeinfo> 
#include <stdio.h> 

using namespace std; 

template<typename MOLECULE1, typename MOLECULE2> 
void printPotential(MOLECULE1 *mol1, MOLECULE2 *mol2) { 
    double my_potential = mol1->potential(mol2); 
    printf("%f",my_potential); 
} 

class Col; 

class LC 
{ 
    public: 
    /// more data and functions should be here regarding the LC molecule 
    double potential(const LC * mol) {return 2;} 
    double potential(const Col * mol) {return 3;} 
}; 
class Col 
{ 
    public: 
    /// more data and function should be here regarding the Col molecule 
    double potential(const LC * mol) {return 5;} 
    double potential(const Col * mol) {return 6;} 
}; 


int main(int argc, char* argv[]) 
{ 
    Col *mol1 = new Col(); 
    LC *mol2 = new LC(); 

    printPotential(mol1, mol2); 
} 

其实,在写这个我觉得可能是第三个(实际上是推荐)方法:你需要找到一个抽象算法如何通过仅使用可以是基类的一部分的公共信息(或通过基类的虚函数调用而获得)来计算两个分子之间的势能。在这种情况下,您可以只有一个潜在的实现()(或者作为基类的成员函数,带有Molecule *类型的单个参数,或者作为具有Molecule *类型的两个参数的非成员函数)。如果我认为这两个分子之间的电势是两个“绝对”电位(就像一个哑巴为例)的不同,它可能是这样的:

#include <iostream> 
#include <typeinfo> 
#include <stdio.h> 

using namespace std; 
class Col; 
class LC; 

class Molecule 
{ 
    public: 
    virtual ~Molecule() {} 
    /// more data and functions should be here regarding the molecule 
    double potential(const Molecule * mol) { 
    return mol->getAbsolutePotential() - getAbsolutePotential(); 
    } 
    virtual double getAbsolutePotential() const = 0; 
}; 

class LC : public Molecule 
{ 
    public: 
    virtual ~LC() {} 
    /// more data and functions should be here regarding the LC molecule 
    double getAbsolutePotential() const {return 42.0;} 
}; 
class Col : public Molecule 
{ 
    public: 
    virtual ~Col() {} 
    /// more data and function should be here regarding the Col molecule 
    double getAbsolutePotential() const {return 120.0;} 
}; 


int main(int argc, char* argv[]) 
{ 
    Molecule * mol1 = new Col(); 
    Molecule * mol2 = new LC(); 

    double my_potential = mol1->potential(mol2); 
    printf ("%f",my_potential); 
} 
+0

我认为动态解决方案更像面向对象设计。 如果您认为模板更适合这里,我会很高兴看到这种解决方案。我也修正了返回6的错误,thx! – pio

+1

查看我的答案编辑:-) –