如何使用多态参数动态调用函数
How to call function dynamically with polymorphism argument
如何动态调用以下形式的函数:childA.function(childB)
而它们的静态类型都是父类?
以及更多详情:
我有一个物理项目,我需要计算 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 的静态类型是 Molecule,因此调用的函数是:
virtual double potential(const Molecule * mol) {return 4;}
而不是
virtual double potential(const LC * mol) {return 5;}
有没有在不使用 typeid 的情况下动态调用函数(在 OOP 设计中)的方法?
完整答案:
After investigation with Peter advice this turn out to be classical double-dispatch problem the full solution is just to call another virtual inside the virtual like this:
#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);
}
这确实是 return 3 所希望的。
您总是调用 potential(Molecule*),因为这是您传递的参数类型。
如果您想动态地执行此操作(即做出运行时决定),您将必须进行动态转换以确定您实际拥有的类型,然后调用正确的函数。你可以例如仅在基 class 中使用基类型参数实现函数,检查实际类型,然后使用正确的类型调用重载函数。代码可能如下所示:
#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 并调用了 Col。我还添加了缺少的虚拟析构函数,因为多态 class es 应该总是有它。
或者,您可以尝试使用模板代码实现它,并首先避免使用运行时多态性(即永远不要持有 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);
}
实际上,在写这篇文章时,我认为可能有第三种(实际上是首选的)方法:您需要找到一种抽象算法,如何通过仅使用公共信息来计算两个分子之间的势能,这些信息可能是分子的一部分base class(或通过base class的虚函数调用获得)。在这种情况下,你可以有一个 potential() 的单一实现(作为基 class 的成员函数,带有一个 Molecule* 类型的参数,或者作为一个非成员函数,带有两个 Molecule* 类型的参数).如果我假设两个分子之间的电势是两个 "absolute" 电势之差(就像一个愚蠢的例子),它可能看起来像这样:
#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);
}
如何动态调用以下形式的函数:childA.function(childB)
而它们的静态类型都是父类?
以及更多详情:
我有一个物理项目,我需要计算 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 的静态类型是 Molecule,因此调用的函数是:
virtual double potential(const Molecule * mol) {return 4;}
而不是
virtual double potential(const LC * mol) {return 5;}
有没有在不使用 typeid 的情况下动态调用函数(在 OOP 设计中)的方法?
完整答案:
After investigation with Peter advice this turn out to be classical double-dispatch problem the full solution is just to call another virtual inside the virtual like this:
#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);
}
这确实是 return 3 所希望的。
您总是调用 potential(Molecule*),因为这是您传递的参数类型。
如果您想动态地执行此操作(即做出运行时决定),您将必须进行动态转换以确定您实际拥有的类型,然后调用正确的函数。你可以例如仅在基 class 中使用基类型参数实现函数,检查实际类型,然后使用正确的类型调用重载函数。代码可能如下所示:
#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 并调用了 Col。我还添加了缺少的虚拟析构函数,因为多态 class es 应该总是有它。
或者,您可以尝试使用模板代码实现它,并首先避免使用运行时多态性(即永远不要持有 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);
}
实际上,在写这篇文章时,我认为可能有第三种(实际上是首选的)方法:您需要找到一种抽象算法,如何通过仅使用公共信息来计算两个分子之间的势能,这些信息可能是分子的一部分base class(或通过base class的虚函数调用获得)。在这种情况下,你可以有一个 potential() 的单一实现(作为基 class 的成员函数,带有一个 Molecule* 类型的参数,或者作为一个非成员函数,带有两个 Molecule* 类型的参数).如果我假设两个分子之间的电势是两个 "absolute" 电势之差(就像一个愚蠢的例子),它可能看起来像这样:
#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);
}