嘿所以我正在尝试构建类 ConcavePolygon 的以下成员Functors,并且由于某种原因我得到了Linker External符号错误:
未解析的外部符号“public:virtual void __thiscall sf :: ConcavePolygon :: Partition :: RunAlgorithm(类TPPLPoly&,类 std :: list> &安培)“
我的目标是简单地创建一个包含SFML(lib)可以理解的图形数据的类,并将其用于分区或三角化图形数据(Polygon(s))
而不是用非常相似的代码编写两个大函数;一个到Triangulate,一个做我称之为Convexulating,我决定尝试使用仿函数,并使基础算符 分区,后代Triangulate和Convexulate 。
基类Partition只包含两个函数:
我认为错误与虚拟RunAlgorithm函数有关,因为它是由构造函数依赖的,但我猜测它后代以某种方式呈现为无效。
如何实现目标或解决此问题?
以下是代码:
class ConcavePolygon : public Body{
protected:
std::list<Vector2f> SFMLPoints;
std::vector <TPPLPoint> TPPLPoints; //TODO: figure out how to make a temp version without Memory Exception
public:
//////////////////// Partitioning/Triangulating Classes /////////////////////////////////////////////////////////////
class Partition{
public:
virtual void RunAlgorithm(TPPLPoly& Poly, std::list<TPPLPoly>& PartitionOutput);
Partition(){};
Partition(ConcavePolygon* Poly, Vector2f* Points, long numbPoints){ //TODO turn this into a base class for triangulate or Convexulate
//rev up all the needed data structs
std::list<TPPLPoly> PartitionOutput;
std::list <TPPLPoly> ::iterator I;
//Backup the points, and convert them to tppl
for(int I=0; I<numbPoints; I++){
Poly->TPPLPoints.push_back(TPPLPoint(Points[I].x, Points[I].y));
Poly->SFMLPoints.push_back(Points[I]);}
TPPLPoly TempPoly(&Poly->TPPLPoints[0], numbPoints, false);
//clear everything to be filled with the Partition Algorithm
Poly->Clear();
// Run the Partitioning Algorithm (This is an abstract function, and is overloaded)
RunAlgorithm(TempPoly, PartitionOutput);
// Convert results to SFML points, shapes, and add to the body
for( I= PartitionOutput.begin(); I!= PartitionOutput.end();I++){
sf::Shape TempShape;
for(int i=0; i< I->GetNumPoints(); i++)
TempShape.AddPoint( I->GetPoint(i).x, I->GetPoint(i).y);
Poly->AddShape(TempShape);
}
};
};
class Convexulate: public Partition{
public:
Convexulate(ConcavePolygon* Poly, Vector2f* Points, long numbPoints){
Partition(Poly, Points, numbPoints);};
void RunAlgorithm(TPPLPoly& Poly, std::list<TPPLPoly>& PartitionOutput){
TPPLPartition Partition;
Partition.ConvexPartition_OPT(&Poly, &PartitionOutput);
};
};
class Triangulate: public Partition{
public:
Triangulate(ConcavePolygon* Poly, Vector2f* Points, long numbPoints){
Partition(Poly, Points, numbPoints);};
void RunAlgorithm(TPPLPoly& Poly, std::list<TPPLPoly>& PartitionOutput){
TPPLPartition Partition;
Partition.Triangulate_OPT(&Poly, &PartitionOutput);
};
};
////////////////////// Constructors /////////////////////////////////////////////////////
ConcavePolygon(Vector2f* Points, long numbPoints){
Convexulate(this,Points, numbPoints);
};
};// ConcavePolygon Class
答案 0 :(得分:1)
在内部virtual void RunAlgorithm()
内有class Partition
的方法正文或将其声明为纯virtual
:
virtual void RunAlgorithm(TPPLPoly& Poly, std::list<TPPLPoly>& PartitionOutput) = 0;
有一种特殊情况,当声明该类或其子对象时,任何虚函数都不会保持未实现(即使未使用该函数)。
答案 1 :(得分:1)
看起来在Partition的后代中,您没有正确地将调用转发给Partition构造函数。相反,您正在构建一个临时的Partition对象,然后立即将其丢弃。
struct Base {
Base() { cout << "Base Default" << endl; }
Base(int i) { cout << "Base Int: " << i << endl;
~Base() { cout << "~Base" << endl;
}
struct DerivedWrong : Base {
DerivedWrong(int i) {
Base(i);
cout << "Derived Int: " << i << endl;
}
};
如果构造DerivedWrong
对象,则输出应为
Base Default
Base Int: 5
~Base
Derived Int: 5
在派生类构造函数的输出之前看到偷偷摸摸的析构函数调用?这是被摧毁的临时对象。在该临时对象的构造函数中,它尝试调用您未实现的RunAlgorithm
,而不是您的链接器错误。如果您使RunAlgorithm
纯虚拟[顺便说一下你应该这样做],你会得到一个关于构造抽象类型的错误,而不是链接器错误,这可能对你更有用。以下理论上可以解决问题:
struct DerivedRight : Base {
DerivedRight(int i)
: Base(i)
{ cout << "Derived Int: " << i << endl; }
};
在这种情况下,输出就是您所期望的。
Base Int: 5
Derived Int: 5
但是,仍然存在一个问题:您无法从基类构造函数调用虚函数并获得多态行为...您最终会调用函数的基类版本,无论是否已被覆盖。您必须等到对象完全构造才能获得多态行为。
基本上,在构造的每一步中,对象都是正在构造的任何东西。即使它最终是Triangulate
对象,在Partition
的构造函数中,它的行为也是Partition
。这意味着您仍然会遇到链接器错误。
请注意,您仍然可以从构造函数中调用虚方法,您只需要非常了解此行为。如果您确定永远不会派生Triangulate
等,您可以从基类构造函数中提取代码,并将其放在从派生类的构造函数中调用的Init
方法中。在该方法中,虚拟调度将按需运行。
您也可以考虑延迟初始化...存储输入参数,并且仅在第一次执行仿函数时执行计算。之后,只返回缓存的结果。这需要额外的额外开销,但无论最终的继承图最终如何,都具有完全安全的好处。有状态的仿函数有自己的问题,这取决于你打算如何使用这个类。