I have this code for the class IdTask
class IdTask
{
public:
IdTask(QString host, QString id) : _host(host), _id(id) {}
IdTask(const IdTask & idT) : _host(idT._host), _id(idT._id) {}
QString host() const { return _host;}
QString id() const { return _id;}
inline bool operator ==(const IdTask& idT) const { return _host == idT.host() && _id == idT.id();}
inline bool operator <(const IdTask& idT) const { return _host < idT.host() && _id < idT.id();}
private:
QString _host;
QString _id;
};
And the class IdResult
class IdResult
{
public:
IdResult(IdTask idT, QString id) : _idTask(idT), _id(id) {}
IdTask idTask() const { return _idTask;}
QString id() const { return _id;}
bool operator < (const IdResult& idR) const { return _idTask < idR.idTask() && _id < idR.id();}
private:
IdTask _idTask;
QString _id;
};
I create a QMap like this :
QMap<IdResult, QString> mapIdResultInput;
mapIdResultInput.insert(IdResult(IdTask("localhost", "init"), "a"), "_a");
The problem is with the function contains.
mapIdResultInput.contains(IdResult(IdTask("b", "c"), "g"));
It return always true.
What is the problem with my code?
I would solve this in the following way: I would sort my IdResults first by IdTask and than, if IdTasks are equal, by id. Here is my implementation of your operators in the classes:
class IdTask
{
public:
[..]
bool operator ==(const IdTask& idT) const
{ return _host == idT.host() && _id == idT.id(); }
bool operator <(const IdTask& idT) const
{ return (_host < idT.host()) || (_host == idT.host() && _id < idT.id()); }
[..]
};
And
class IdResult
{
[..]
bool operator < (const IdResult& idR) const
{ return (_idTask < idR.idTask()) || (_idTask == idR.idTask() && _id < idR.id()); }
[..]
};
And the test
QMap<IdResult, QString> mapIdResultInput;
mapIdResultInput.insert(IdResult(IdTask("localhost", "init"), "a"), "_a");
bool b = mapIdResultInput.contains(IdResult(IdTask("b", "c"), "g")); // false
b = mapIdResultInput.contains(IdResult(IdTask("localhost", "init"), "a")); // true
Related
I'm trying to solve this simple riddle at codingames and I thought i will exercise in OOP
However, it seems I've forgotten how CPP works in this field and I got an error I do not comprehend.
/tmp/Answer.cpp:82:1: error: invalid abstract return type ‘Sign’
82 | Sign from_str(const int value, const std::string& s)
| ^~~~
/tmp/Answer.cpp:14:7: note: because the following virtual functions are pure within ‘Sign’:
14 | class Sign {
| ^~~~
/tmp/Answer.cpp:22:25: note: ‘virtual std::string Sign::str() const’
22 | virtual std::string str() const = 0;
| ^~~
/tmp/Answer.cpp:82:6: error: invalid abstract return type for function ‘Sign from_str(int, const string&)’
82 | Sign from_str(const int value, const std::string& s)
| ^~~~~~~~
/tmp/Answer.cpp: In function ‘Sign from_str(int, const string&)’:
/tmp/Answer.cpp:85:26: error: cannot allocate an object of abstract type ‘Sign’
85 | return Rock(value);
| ^
/tmp/Answer.cpp:87:27: error: cannot allocate an object of abstract type ‘Sign’
87 | return Paper(value);
| ^
/tmp/Answer.cpp:89:30: error: cannot allocate an object of abstract type ‘Sign’
89 | return Scissors(value);
| ^
/tmp/Answer.cpp:91:28: error: cannot allocate an object of abstract type ‘Sign’
91 | return Lizard(value);
| ^
/tmp/Answer.cpp:93:27: error: cannot allocate an object of abstract type ‘Sign’
93 | return Spock(value);
And the code looks like this:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Rock;
class Paper;
class Scissors;
class Sign {
public:
Sign(const int v): value(v) {};
virtual ~Sign() {};
bool operator<(const Sign& other) { return value < other.value ? false : true; }
virtual std::string str() const = 0;
int value{};
};
class Rock : public Sign {
public:
Rock(const int v): Sign(v) {};
bool operator<(const Paper& other) { return true; }
bool operator<(const Scissors& other) { return false; }
std::string str() const override { return "Rock"; }
};
class Paper : public Sign {
public:
Paper(const int v): Sign(v) {};
bool operator<(const Rock& other) { return true; }
bool operator<(const Scissors& other) { return false; }
std::string str() const override { return "Paper"; }
};
class Scissors : public Sign {
public:
Scissors(const int v): Sign(v) {};
bool operator<(const Rock& other) { return false; }
bool operator<(const Paper& other) { return true; }
std::string str() const override { return "Scissors"; }
};
Sign from_str(const int value, const std::string& s)
{
if(s == "R")
return Rock(value);
if(s == "P")
return Paper(value);
if(s == "C")
return Scissors(value);
throw 1;
}
int main()
{
int N;
cin >> N; cin.ignore();
std::vector<Sign> s{};
for (int i = 0; i < N; i++) {
int NUMPLAYER;
string SIGNPLAYER;
cin >> NUMPLAYER >> SIGNPLAYER; cin.ignore();
s.emplace_back(from_str(NUMPLAYER, SIGNPLAYER));
}
}
At this point, I don't really understand why I can't use Sign as the return value from the factory method that is returning concrete types and emplace it on my data pile.
And if I add to the base class
virtual std::string str() const { return "Sign"; };
I will only get the base class printout.
You are sufferring from object slicing, both in your return type from from_str and in your vector <Sign>.
Like it or not, you are going to have to use pointers, but if you use smart pointers then the pain will go away. So, first change your from_str function like so:
std::unique_ptr <Sign> from_str(const int value, const std::string& s)
{
if(s == "R")
return std::make_unique <Rock> (value);
if(s == "P")
return std::make_unique <Paper> (value);
if(s == "C")
return std::make_unique <Scissors> (value);
throw 1;
}
And then change your vector to:
std::vector<std::unique_ptr <Sign>> s{};
And that's all you need to change. The fact that you're using std::unique_ptr takes care of any memory management issues.
Without allocation, you might use std::variant:
struct Rock
{
std::string str() const { return "Rock"; }
};
struct Paper
{
std::string str() const { return "Paper"; }
};
struct Scissors
{
std::string str() const { return "Scissors"; }
};
using Sign = std::variant<Rock, Paper, Scissors>;
bool winSigns (Paper, Rock) { return true; }
bool winSigns (Rock, Scissors) { return true; }
bool winSigns (Scissors, Paper) { return true; }
template <typename Sign1, typename Sign2>
bool winSigns (Sign1, Sign2) { return false; }
Sign from_str(const std::string& s)
{
if (s == "R")
return Rock{};
if (s == "P")
return Paper{};
if (s == "C")
return Scissors{};
throw 1;
}
int main()
{
std::string SIGNPLAYER1;
std::cin >> SIGNPLAYER1;
Sign sign1 = from_str(SIGNPLAYER1);
std::string SIGNPLAYER2;
std::cin >> SIGNPLAYER2;
Sign sign2 = from_str(SIGNPLAYER2);
std::visit([](auto lhs, auto rhs){
std::cout << lhs.str() << "versus" << rhs.str() << std::endl;
if (winSigns (lhs, rhs)) std::cout << "player1 wins\n";
else if (winSigns (rhs, lhs)) std::cout << "player2 wins\n";
else std::cout << "Draw\n";
}, sign1, sign2);
}
Demo
I want to delete every element at a certain index (that corresponds to a certain content), but I'm getting a segmentation fault... This is the structure of my code and the method deleteRecord is what I've tried but doesn't work:
class Tab {
public:
Tab();
~Tab() {};
bool colIsPresent(const string & col_name);
template <typename S> void deleteRecord(S & content, const string & col_name) {
int delete_pos;
if (!this->colIsPresent(col_name)) return;
const auto & it_columns = _columns.find(col_name);
if (it_columns != _columns.end()) {
auto ci = dynamic_cast<ColumnImpl<S> *>(it_columns->second.get());
if (ci != nullptr) {
for (int i = 0; i < ci->getData().size(); i++) {
if (ci->getData()[i] == content) {
delete_pos = i;
}
for (auto & it_columns_2 : _columns) {
auto ci2 = dynamic_cast<ColumnImpl<S> *>(it_columns_2.second.get());
ci2->getData().erase(ci2->getData().begin() + delete_pos);
}
}
}
}
}
private:
map<string, shared_ptr<Column>> _columns;
};
template <typename T> class ColumnImpl : public Column {
public:
ColumnImpl() : Column() {}
ColumnImpl(const T& to_set);
vector<T> & getData() { return _data; }
protected:
vector<T> _data;
};
class Column {
public:
Column();
virtual ~Column() {};
virtual string getType() = 0;
};
class Database {
public:
Database();
~Database();
bool tabIsPresent(const string & tab_name);
template <typename S> void deleteRecordFromTab(const string & tab_name, S & content, const string & col_name) {
const auto & it_target_tab = _tables.find(tab_name);
it_target_tab->second.deleteRecord(content, col_name);
}
private:
map<string, Tab> _tables;
};
Reproducible example:
Database data_base;
string tab = "EX_TAB", str1 = "STR_EX1", str2 = "STR_EX2", age = "AGE", name = "NAME", integer = "INT", text = "TEXT";
int a = 17, b = 18;
data_base.createNewTable(tab);
data_base.addColumnToTab(tab, age, integer);
data_base.addColumnToTab(tab, name, text);
data_base.addElemToColOfTab(tab, age, a);
data_base.addElemToColOfTab(tab, age, b);
data_base.addElemToColOfTab(tab, name, str1);
data_base.addElemToColOfTab(tab, name, str2);
data_base.deleteRecordFromTab(tab, str1, name);
// createNewTable creates a new table
// addColumnToTab adds a new column of the right type to _columns
// addElemToColumnOfTab adds an element to the targeted column
There is a base class
class LineEditItem
{
public:
LineEditItem(QLineEdit* le, const Values_t& values = Values_t()):
values(values),
le(le)
{}
LineEditItem &addValue(int v, const QString &s)
{
values[v] = s;
return *this;
}
LineEditItem &addValues(const Values_t& vals)
{
for (auto key: vals.keys())
{
values[key] = vals[key];
}
return *this;
}
void setValue(uint32_t v)
{
QString str;
if (values.contains(v))
{
str = values[v];
}
else
{
str = "";
}
le->setText(str);
}
void clearValue()
{
le->clear();
}
protected:
Values_t values;
QLineEdit* le;
};
There is a child class that must inherit the addValue and addValues methods
class LineEditItemBits: public LineEditItem
{
public:
LineEditItemBits(QLineEdit* le, int begin, int end, const Values_t& values = Values_t()):
LineEditItem(le, values),
begin(begin),
end(end)
{}
void setValue(uint32_t v)
{
int s = end - begin + 1;
v = (v >> begin) & ((1 << s) - 1);
LineEditItem::setValue(v);
}
LineEditItemBits &addValue(int v, const QString &s)
{
LineEditItem::addValue(v, s);
return *this;
}
LineEditItemBits &addValues(const Values_t& vals)
{
LineEditItem::addValues(vals);
return *this;
}
private:
int begin;
int end;
};
But you have to explicitly prescribe these methods and call base class methods from them.
How to inherit these methods from the base class so that they return a reference to the child class?
From my understanding you are trying to override these functions, so you should make them virtual in parent class.
I get a segfault while iterating over a QList. I don't understand what I am doing wrong.
I have a QList of Conversation. Inside a Conversation I have a QList of Msg. Below are the class description :
Msg class :
class Msg {
public:
Msg();
Msg(const Msg& other);
Msg& operator=(const Msg& other);
virtual ~Msg();
bool operator==(const Msg& other);
QString id() const { return _id; }
MsgContact author() const { return _author; }
MsgContact dest() const { return _dest; }
QDateTime date() const { return _receivedDate; }
MsgDirection direction() const { return _direction; }
QString text() const { return _text; }
bool transmitted() const { return _transmitted; }
void setId(const QString& id) { _id = id; }
void setAuthor(const MsgContact& author) { _author = author; }
void setDest(const MsgContact& dest) { _dest = dest; }
void setDate(const QDateTime& receivedDate) { _receivedDate = receivedDate; }
void setDirection(const MsgDirection& direction) { _direction = direction; }
void setText(const QString& text) { _text = text; }
void setTransmitted(const bool& transmitted) { _transmitted = transmitted; }
private:
QString _id;
MsgContact _author;
MsgContact _dest;
QDateTime _receivedDate;
MsgDirection _direction;
QString _text;
bool _transmitted; //indique que le message a été transmis
bool _read; //indique la lecture
};
Conversation class :
class Conversation
{
public:
Conversation();
Conversation(const Conversation& other);
virtual ~Conversation();
Conversation& operator=(const Conversation& other);
bool operator==(const Conversation& other);
bool isNull() const { return (NULL == _title || NULL == _destId); }
const QString title() const { return _title; }
const QString destId() const { return _destId; }
QList<Msg> messages() const { return _messages; }
void setDestId(const QString& destId) { _destId = destId; }
void setTitle(const QString& title) { _title = title; }
void addMsg(const Msg& msg);
static Conversation INVALID_CONVERSATION;
private:
QList<Msg> _messages;
QString _title;
QString _destId;
};
void Conversation::addMsg(const Msg& msg)
{
_messages.append(msg);
}
Code that generate the segfault. I create a message, I iterate over the Conversation list to add the message in the related conversation. Then, i want to iterate over the message list and I get a segfault. I use different way to access to the message which works fine.
Msg *m = new Msg();
m->setId(xmppMsg.id());
m->setDest(findContactById(conversationId));
m->setDirection(MsgOutgoing);
m->setAuthor(_myContact);
m->setText(message);
m->setDate(xmppMsg.stamp());
QList<Conversation>::iterator it;
for(it = _conversations.begin(); _conversations.end() != it; it++)
{
if((*it).destId() == conversationId)
{
(*it).addMsg(*m);
Q_EMIT(conversationChanged((*it)));
break;
}
}
qDebug() << "NB : " <<(*it).messages().size(); // ok, the number of message is incremented.
//test several way of accessing a message, these works fine.
qDebug() << "doSend " << it->messages().at(0).id();
qDebug() << "doSend " << it->messages().begin()->id();
qDebug() << "doSend " << (*(it->messages().begin())).id();
//try to iterate
QList<Msg>::iterator msgIt = it->messages().begin();
if(msgIt != it->messages().end())
{
qDebug() << "TEST - "<< msgIt->id(); //segfault.
}
Thank you for your help
(Edited away first "answer", this is an actual attempt at an answer)
My guess:
QList<Msg> messages() const { return _messages; }
It's returning a copy of the QList _messages, rather than a reference to it. I'm not sure that it would give the results you're seeing, but it looks wrong to me. Maybe try something like this?
QList<Msg>& messages() const { return _messages; }
For some reason I need to use string with fixed size. Now I'm looking on a QString class.
But there I have some questions with making QString object having constant size.
For example, I want to have string with size 10, it means, that if I would try to write some string with more than 100 chars in it, it would cut all the characters after 100 one.
I found constructor for QString in Qt docs, but I'm not sure if it would work as I told
QString( int size , QChar ch)
What can you suggest in such situation?
You can have a wrapper class that has a string, but is not a string, yet it can be used wherever a QString could be used. It can also be used with all QString's methods and operators, as long as you treat it like it were a pointer.
#include <QString>
class FixedWidthString {
mutable QString m_string;
//! Ignored if negative.
int m_maxLength;
inline const QString& data() const {
if (m_maxLength >= 0 && m_string.length() > m_maxLength)
m_string.truncate(m_maxLength);
return m_string;
}
inline QString& data() {
if (m_maxLength >= 0 && m_string.length() > m_maxLength)
m_string.truncate(m_maxLength);
return m_string;
}
public:
explicit FixedWidthString(int maxLength = -1) : m_maxLength(maxLength) {}
explicit FixedWidthString(const QString & str, int maxLength = -1) : m_string(str), m_maxLength(maxLength) {}
operator const QString&() const { return data(); }
operator QString&() { return data(); }
QString* operator->() { return &data(); }
const QString* operator->() const { return &data(); }
QString& operator*() { return data(); }
const QString& operator*() const { return data(); }
FixedWidthString & operator=(const FixedWidthString& other) {
m_string = *other;
return *this;
}
};
int main() {
FixedWidthString fs(3);
FixedWidthString fs2(2);
*fs = "FooBarBaz";
Q_ASSERT(*fs == "Foo");
fs->truncate(2);
Q_ASSERT(*fs == "Fo");
fs->append("Roo");
Q_ASSERT(*fs == "FoR");
fs->truncate(1);
*fs += "abc";
Q_ASSERT(*fs == "Fab");
fs2 = fs;
Q_ASSERT(*fs2 == "Fa");
}