Базовый вопрос Пожалуйста, прочитайте этот вопрос, даже если у вас нет времени, чтобы взглянуть на все остальные детали. 🙂
— Мне нужно хранить несколько объектов моего пользовательского класса (Tuple) в наборе. Этот класс содержит только вектор строки. (Как того требует проект). Как мне реализовать это так, чтобы он распознавал каждый элемент уникально (и, следовательно, исключал только идентичные векторы)? 2 — мой профессор предложил мне наследовать векторную строку в моем пользовательском классе (Tuple), чтобы мне не пришлось писать свой собственный оператор «<»
Более подробная информация, если у вас есть время 🙂
Я немного посмотрел в Интернете и не нашел решения своей проблемы. Прежде всего, я признаю, что это школьное задание (простая реляционная база данных), поэтому у меня есть некоторые требования (даже если я сейчас не понимаю, почему некоторые из этих вещей должны быть выполнены таким образом).
Обязательные классы
—> «Отношение» ——> должен использовать std :: set для хранения кортежей
—> «Tuple» ——> это список «значений атрибутов»
Мне дали подсказку в классе, что если бы я расширил вектор строки, я бы не стал писать свой собственный оператор< в классе «Кортеж». Я не знаю, это кошерное предложение, которое дал мой профессор, но мне не нужно писать сложный оператор< класс звучит привлекательно для меня.
Проблема:
Мне нужно хранить набор «кортежей» класса, который я собираюсь создать. У меня сейчас проблема в том, что хранится только первый «кортеж». Я использовал вектор рядом с набором, чтобы видеть, пытается ли мой код делать то, что я хочу, и похоже, что моя проблема в том, что набор распознает каждый «кортеж», который я вставляю, как эквивалент уже существующего «кортежа» таким образом, я получаю набор только из 1 «кортежа», хотя у меня должно быть больше.
Я включил код, который я вижу соответствующим образом ниже. Чтобы не смотреть на многие вещи, внизу я покажу функцию, которая вставляет новые «кортежи» в уже существующее «отношение», если вы посмотрите в класс «отношение», то увидите функцию «insertTuple (Tuple»). tupIn);» который получает кортеж и добавляет его к рассматриваемому набору.
Что мне нужно знать?
Спасибо, StackOverflow, вы — группа умных, терпеливых людей!
Tuple.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();
};
Tuple.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;
}
Relation.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();
};
Relation.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)));
}
}
}
}
Проблема в том, что вы наследуете от вектора, чтобы не писать свой собственный оператор<, но вы храните данные в векторе-члене. Унаследованный оператор< не имеет представления о векторе-члене, и поскольку вы никогда ничего не добавляете в унаследованный вектор, все ваши объекты сравниваются как одинаковые, поскольку все пустые векторы одинаковы.
Наследование от стандартного контейнера будет работать, но это не всегда лучшая идея, так как у них нет виртуального деструктора. Для этого задания все должно быть в порядке, но вы должны провести некоторое исследование, чтобы вы знали о проблемах в будущем.
Вот пример, который демонстрирует проблему с вашим текущим кодом, а также показывает две альтернативы, использующие наследование и вектор-член. Я бы порекомендовал вектор-член, поскольку он позволяет избежать проблем наследования от стандартного контейнера и оператора.< это только одна строка, но это зависит от вас.
#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;
}