我实际上并没有遇到“问题”,因为我的代码确实起作用。我只是好奇我的实现是否合理且无风险。
我一直在使用C ++开发项目,在该项目中,我首先解析文件,然后相应地构建有向无环图结构。每个节点可以有0〜2个邻居,具体取决于节点的类型。对于不同类型的节点,需要一些用于打印和访问的功能,我决定使用多态性来进行操作。
我的第一个尝试是使用存储指向其邻居的指针的节点来实现它。
class Base{
public:
Base(){}
virtual ~Base(){}
virtual foo()=0;
// ...
protected:
unsigned _index;
}
class Derived1: public Base{
public:
foo(){ /*Do something here...*/ }
private:
Base* _out1;
}
class Derived2: public Base{
public:
foo(){ /*Do something different here...*/ }
private:
Base* _out1;
Base* _out2;
}
int main(){
std::vector<Base*> _nodeList;
for(/*during parsing*/){
if(someCondition){
_nodeList.pushback(new Derived1);
}
// ...
}
}
由于节点的邻居可能尚未定义何时构造节点,因此我必须添加一些技巧以首先记住邻居的ID,并在完成所有节点的构造之后将它们连接起来。
但是,由于确定了要解析的文件的节点数量,并且以后不会再增加,因此我认为最好连续存储所有节点,并且每个节点都存储其邻居索引而不是指针。这使我可以跳过连接部分,并为其他部分带来一些小好处。
我当前的版本如下:
// Something like this
class Base{
public:
Base(){}
virtual ~Base(){}
virtual foo()=0;
// ...
protected:
unsigned _index;
unsigned _out1;
unsigned _out2;
}
class Derived1: public Base{
public:
foo(){ /*Do something here...*/ }
}
class Derived2: public Base{
public:
foo(){ /*Do something a little bit different here...*/ }
}
int main(){
// EDITED!!
// Base* _nodeList = new DefaultNode[max_num];
Base* _nodeList = new Derived2[max_num];
for(/*during parsing*/){
if(someCondition){
// EDITED!!
// _nodeList[i] = Derived1;
new(_nodeList+i) Derived1();
}
// ...
}
}
将不同类的对象存储在new
数组中是否存在风险,因为它们的大小均相同,并且可以使用虚拟析构函数对其进行破坏?
我一直听说应该避免使用new[]
。我确实找到了一些方法,可以使用带有类型标签的vector
的union
实现我想要的功能,但对我来说似乎有些肮脏。在std::vector
中存储数据时,有一种方法可以实现多态吗?
使用多态性只是为了利用虚函数的便利性的做法是否被视为一种坏习惯?这么说是指如果每个对象所占用的内存对于每个派生类而言都是相同的,则可以将它们合并为一个存储自己类型的单个类,并且每个成员函数都可以根据自己的类型运行。我选择不这样做,因为在每个成员函数中都具有巨大的switch
结构对我来说也很脏。
在这种情况下选择连续内存好吗?是否有任何理由认为这样的选择可能有害?
编辑:
事实证明,我犯了很多错误,例如一次要问太多问题。我想我将首先关注具有多态性和新位置的部分。以下是一个可测试的程序,其含义是“将不同派生类的对象存储在新数组中,并且在笔记本电脑上的行为如下所示。
#include <iostream>
class Base{
public:
Base(){}
virtual ~Base(){}
void virtual printType() =0;
};
class Derived1: public Base{
public:
Derived1(){}
void printType(){ std::cout << "Derived 1." << std::endl; }
};
class Derived2: public Base{
public:
Derived2(){}
void printType(){ std::cout << "Derived 2." << std::endl; }
};
int main(){
Base* p = new Derived1[5];
new(p+2) Derived2();
for(unsigned i = 0; i < 5; ++i){
(p+i)->printType();
}
}
结果:
Derived 1.
Derived 1.
Derived 2.
Derived 1.
Derived 1.
再次感谢您的所有反馈和建议。
- 如果它们具有相同的大小并且可以被销毁,那么将不同类的对象存储在新数组中存在任何风险。使用虚拟析构函数?
这不是你的第二个命题:
Base* _nodeList = new DefaultNode[max_num];
_nodeList
是DefaultNote
的数组,仅此而已!尝试在其中存储诸如_nodeList[i] = ...
之类的内容将[[never不会更改有关存储对象性质的任何内容(请注意,_nodeList[i] = Derived1;
不是C ++)。如果要多态,则需要通过指针或引用保留对象。那么第一个解决方案是正确的解决方案:std::vector<Base*> _nodeList;
。
我一直听说应该避免使用new []。我确实发现了一些使用联合向量实现我想要的方法带有类型标签,但对我来说似乎有点脏。有没有办法在将数据存储到std :: vector时实现多态?
应避免使用new []是胡说八道。如前所述,如果您需要多态性,那么std::vector<Base*> _nodeList;
是完美的,因为这意味着您可以将_nodeList
或其任何子类型的任何对象的地址存储在Base
中。是仅使用多态来利用虚拟函数的便利性是否有坏习惯?这样说我表示每个对象占用的内存是否已经相同派生类,则可以将它们合并为一个存储自己的类型,每个成员函数都可以根据到自己的类型。我选择不这样做,因为它在我看来也很脏在每个成员函数中都有巨大的开关结构。
是使用虚函数。为什么有坏习惯?如果您不使用虚函数,则仅意味着您自己构建多态,这可能是一件非常糟糕的事情。
在这种情况下选择连续内存好吗?是否有任何理由认为这样的选择可能有害?
我不确定您为什么要为此担心。连续内存无害...这个问题至少不清楚。