使用集合存储自定义类,只有第一个插入有效
Posted
技术标签:
【中文标题】使用集合存储自定义类,只有第一个插入有效【英文标题】:Using a set to store a custom class, only the first insert works 【发布时间】:2014-08-02 22:02:10 【问题描述】:基本问题 请阅读此问题,即使您没有时间查看所有其他详细信息。 :) - 我需要将我的自定义类(元组)的多个对象存储到一个集合中。该类仅包含一个字符串向量。 (根据项目要求)。我如何实现这一点,以便它唯一地识别每个元素(因此只消除相同的向量)? 2 - 我的教授建议我可以从自定义类(元组)中的向量字符串继承,这样我就不必编写自己的“运算符
1 - 这是真的吗? 2 - 如果没有,我是否可以使用继承来获得此功能?更多细节,如果你有时间:)
我在网上看了一会儿,还没有找到解决问题的方法。首先,我承认这是一项学校作业(一个简单的关系数据库),所以我有一些要求要遵循(即使我现在不明白为什么要这样做)。
必修课
--> “关系” ------> 必须使用 std::set 来保存元组
-->“元组” ------> 是“属性值”的列表
我在课堂上得到提示,如果我扩展字符串向量,我不会在“元组”类中编写自己的运算符
问题: 我需要存储一组“元组”我要创建的类。我现在遇到的问题是只存储了第一个“元组”。我在集合旁边使用了一个向量,这样我就可以查看我的代码是否正在尝试做我想做的事情,看起来我的问题是集合正在识别我插入的每个“元组”等同于已经存在的“元组” ,因此我最终得到了一组只有 1 个“元组”,即使我应该有更多。
我在下面包含了我认为相关的代码。为了不让你看太多东西,在底部我展示了将新的“元组”插入到已经存在的“关系”中的函数,如果你查看 Relation 类,你会看到函数“insertTuple(Tuple tupIn);"它接收一个元组并将其添加到相关集合中。
我需要知道什么?
为什么集合中只存储一个项目? 如何解决此问题,以便所有非重复项目都存储在集合中? (假设我并不是所有的插入都是重复的,因为它们不是)。感谢 ***,你们是一群聪明、有耐心的人!
元组.h
#include <iostream>
#include <vector>
#include "DatalogProgram.h"
using namespace std;
class Tuple : public vector<string>
private:
vector<string> attributevals;
public:
Tuple();
Tuple(Predicate input);
~Tuple();
vector<string> returnAttributeVals();
string toString();
;
元组.cpp
#include "Tuple.h"
Tuple :: Tuple()
Tuple :: Tuple(Predicate input)
// Here I will populate the tuple!
attributevals.clear();
for(int x = 0; x < input.returnParams().size(); x++)
//cout << "Adding value to Tuple: " << endl;
//cout << input.returnParams().at(x).toString() << endl;
attributevals.push_back(input.returnParams().at(x).toString());
Tuple :: ~Tuple()
attributevals.clear();
vector<string> Tuple :: returnAttributeVals()
return attributevals;
string Tuple :: toString()
string value = "";
for(int x = 0 ; x < attributevals.size() ; x++)
value = value + attributevals.at(x) + " -|- ";
return "Attribute Values : \n" + value;
关系.h
#include <iostream>
#include <set>
#include <vector>
#include <string>
#include "Scheme.h"
#include "Tuple.h"
//#include "DatalogProgram.h"
#pragma once
using namespace std;
class Relation
private:
string Rname;
Scheme Rscheme;
set<Tuple> Rtuples;
vector<Tuple> RtempVec;
public:
Relation(string nameIn, Scheme schemeIn);
Relation(string nameIn, Scheme schemeIn, set<Tuple> tuplesIn);
~Relation();
void insertTuple(Tuple tupIn);
void select();
void project();
void rename();
void testOutput();
string returnName();
Scheme returnScheme();
set<Tuple> returnTuples();
string toString();
;
关系.cpp #include "Relation.h"
Relation :: Relation(string nameIn, Scheme schemeIn)
Rname = nameIn;
Rscheme = schemeIn;
Relation :: Relation(string nameIn, Scheme schemeIn, set<Tuple> tuplesIn)
Rname = nameIn;
Rscheme = schemeIn;
Rtuples = tuplesIn;
Relation :: ~Relation()
Rname.clear();
Rscheme.clear();
Rtuples.clear();
void Relation :: insertTuple(Tuple tupIn)
cout << Rname << " -> Inserting the following Tuple : \n" << tupIn.toString() << endl;
Tuple temp = tupIn;
Rtuples.insert(temp);
cout << "Current # of tuples in this relation" << Rtuples.size() << endl;
RtempVec.push_back(temp);
string Relation :: returnName()
return Rname;
Scheme Relation :: returnScheme()
return Rscheme;
set<Tuple> Relation :: returnTuples()
return Rtuples;
string Relation :: toString()
cout << "Printing Relation " + Rname << endl;
cout << "Number of Tuples: " << Rtuples.size() << endl;
cout << "Number of tuples in temp Vector" << RtempVec.size() << endl;
set<Tuple> temp = Rtuples;
string result = "";
result = Rname + "\n" + Rscheme.toString() + "\n";
std::set<Tuple>::iterator setiter;
for(setiter = Rtuples.begin(); setiter!=Rtuples.end();setiter++)
cout << "looping through tuples" << endl;
Tuple temp = *setiter;
result = result + " " + temp.toString() + "'\n";
return result;
void select();
void project();
void rename();
void testOutput();
现在我已经包含了比任何人都想看的更多的代码,但这里是创建我试图插入到关系中的元组的函数(进入集合)。
void Database :: ProcessFacts(vector<Predicate> input)
// So for facts I need to match the ID, then add the Paramaters to the tuple in the relation.
// this means I itterate through the Relations already present, if it maches then I add a tuple!
for (int x = 0; x < Drelations.size(); x++)
for(int y = 0; y < input.size() ; y++)
if(input.at(y).returnID() == Drelations.at(x).returnName())
cout << "adding a tuple to --> " << Drelations.at(x).returnName() << endl;
cout << "Tuple is: " << Tuple(input.at(y)).toString() << endl;
Drelations.at(x).insertTuple(Tuple(input.at(y)));
【问题讨论】:
你可能想在这里发布更少的代码,如果需要的话,把它放在像liveworkspace这样的网站上。此外,在调查您不理解的问题时,尤其是与他人分享时,请尝试生成minimal case。祝你好运;) @Antoine 可以!谢谢。 看起来你从向量继承,但实际上并没有在继承的向量中存储任何东西,你没有覆盖operator<
,所以你所有的元组都被比较为空向量,它们都是相同的.根据您的编辑,如果鼓励您从 vector
继承,这通常是一个坏主意,您应该删除 attributevals
并将字符串存储在您继承的对象中,所以只需 push_back(...)
@RetiredNinja 迄今为止最有用的输入!我将如何实现这一点,以便将我的信息存储在继承的向量中,从而继承正确的 operator
目前您的元组有 2 个向量:一个是继承的,一个在 attributevals 字段中。您存储在字段中,但
【参考方案1】:
问题是您从向量继承以避免编写自己的运算符
从标准容器继承是可行的,但这并不总是最好的主意,因为它们没有虚拟析构函数。对于这个作业应该没问题,但你应该做一些研究,以便了解未来的问题。
这是一个示例,它演示了您当前代码的问题,并显示了使用继承和成员向量的两个替代方案。我推荐成员向量,因为它避免了从标准容器继承的问题,并且 operator
#include <cstdlib>
#include <iostream>
#include <set>
#include <string>
#include <vector>
class ProblemTuple : public std::vector<std::string>
public:
void AddAttribute(const std::string& item)
attributes.push_back(item);
void Print() const
for(const std::string& a : attributes)
std::cout << a << " ";
std::cout << "\n";
private:
std::vector<std::string> attributes;
;
class InheritedTuple : public std::vector<std::string>
public:
void AddAttribute(const std::string& item)
push_back(item);
void Print() const
for(const std::string& a : *this)
std::cout << a << " ";
std::cout << "\n";
;
class CompositeTuple
public:
void AddAttribute(const std::string& item)
attributes.push_back(item);
void Print() const
for(const std::string& a : attributes)
std::cout << a << " ";
std::cout << "\n";
bool operator<(const CompositeTuple& rhs) const
return attributes < rhs.attributes;
private:
std::vector<std::string> attributes;
;
std::string randomString()
std::string ret;
for(int i = 0; i < 3; ++i)
ret += 'a' + (std::rand() % 26);
return ret;
template<typename T>
void PrintSet(const std::string& title, const std::set<T>& set)
std::cout << title << "\n";
for(const auto& s : set)
std::cout << " ";
s.Print();
int main()
//Not calling srand on purpose so the result should be the same every time.
std::set<ProblemTuple> ProblemSet;
std::set<InheritedTuple> InheritedSet;
std::set<CompositeTuple> CompositeSet;
for(int i = 0; i < 3; ++i)
ProblemTuple pt;
InheritedTuple it;
CompositeTuple ct;
for(int j = 0; j < 3; ++j)
std::string s(randomString());
pt.AddAttribute(s);
it.AddAttribute(s);
ct.AddAttribute(s);
ProblemSet.insert(pt);
InheritedSet.insert(it);
CompositeSet.insert(ct);
PrintSet("Problem", ProblemSet);
PrintSet("Inherited", InheritedSet);
PrintSet("Composite", CompositeSet);
return 0;
【讨论】:
很好的帮助!感谢您花时间解释这一点,希望这不仅对我有用,而且对其他对继承缺乏类似理解的人有用。以上是关于使用集合存储自定义类,只有第一个插入有效的主要内容,如果未能解决你的问题,请参考以下文章
自定义的Node类和集合类linkedList<Item>的区别?
Swift-自定义 UITableViewCell 委托给 UIViewController 只有一个协议有效