c++ initialize char array member of a class with a string - c++

i have a class which has several members of char arrays, and i want to initialize this class with an array of strings which are the values of the char arrays.
class Product {
public:
char productId[20];
char productName[50];
char price[9];
char stock[9];
Product(vector<string> v) : productId(v[0]), productName(v[1]), price(v[2]), stock(v[3]) { }
};
with this code i get an error that say no suitable conversion function from "str::string" to "char[20]" exist

The code at the bottom will work. But is this a good idea? Probably not. You are better of just storing std::string in your Product type directly:
#include <cassert>
#include <iostream>
#include <vector>
#include <string.h>
class Product {
public:
std::string productId;
...
Product(std::vector<std::string> v) : productId{std::move(v[0])} {}
};
There is a problem with this code though; where do you check the vector has all required elements? Better to make an interface that specifies the four strings a Product is made up of separately:
class Product {
public:
std::string productId;
...
Product(std::string pid, ...) : productId{std::move(pid)}, ... {}
};
But in case you insist on a C/C++ amalgamation;
#include <cassert>
#include <vector>
#include <string.h> // strcpy
class Product {
public:
char productId[20];
char productName[50];
char price[9];
char stock[9];
Product(const std::vector<std::string> &v) {
assert(!v.empty()); // really; v.size() == 4
::strncpy(productId, v[0].c_str(), 19);
productId[19] = '\0';
// ...etc.
}
};

Related

C++ How to place data in vector of base class

Here is my base class:
#include <string>
#include "DataStruct.h"
#include <vector>
#include <mysqlx/xdevapi.h>
#include <iostream>
#include <memory>
namespace Vibranium {
using namespace mysqlx;
class MySQLTable {
public:
MySQLTable();
virtual ~MySQLTable() = default;
int Index;
std::string tableName;
DataStruct dataStruct;
std::vector<std::unique_ptr<DataStruct>> Data;
Table getTable(Session& conn) const;
RowResult getAll(Session& conn) const;
virtual void LoadTable(RowResult& res) {}
};
}
#endif //VIBRANIUM_CORE_MYSQLTABLE_H
Which is representing all MySQL tables i might have. Take a look at Data vector of types DataStruct. I use DataStruct as a base struct because all tables will have different structure.
Here is base DataStruct struct:
namespace Vibranium{
struct DataStruct{};
}
Than I define my first mysql tablle Accounts:
#include <string>
#include "Database/DataStruct.h"
#include "Database/MySQLTable.h"
namespace Vibranium{
using namespace std;
struct AccountsStruct : DataStruct{
int id;
std::string email;
std::string warTag;
int state;
std::string name;
std::string lastname;
std::string country;
int dob_month;
int dob_day;
int dob_year;
double balance;
std::string created_at;
std::string updated_at;
int account_role;
int rank;
int playerRole;
};
class Accounts : public MySQLTable{
public:
Accounts() = default;
void LoadTable(RowResult& res) override;
};
}
As you can see inside I have defined AccountsStruct as child of DataStruct.
Here is how I implement LoadTable:
#include "Accounts.h"
using namespace Vibranium;
void Vibranium::Accounts::LoadTable(RowResult &res) {
std::vector<AccountsStruct> accounts;
AccountsStruct accountsStruct;
for (Row row : res.fetchAll()){
accountsStruct.id = row[0].get<int>();
accountsStruct.email = row[1].get<std::string>();
accountsStruct.warTag = row[2].get<std::string>();
accountsStruct.state = row[4].get<int>();
accountsStruct.name = row[5].get<std::string>();
accountsStruct.lastname = row[6].get<std::string>();
accountsStruct.country = row[7].get<std::string>();
accountsStruct.dob_month = row[8].get<int>();
accountsStruct.dob_day = row[9].get<int>();
accountsStruct.dob_year = row[10].get<int>();
accountsStruct.balance = row[11].get<double>();
accountsStruct.created_at = row[12].get<std::string>();
accountsStruct.updated_at = row[13].get<std::string>();
accountsStruct.account_role = row[15].get<int>();
accountsStruct.rank = row[16].get<int>();
accountsStruct.playerRole = row[17].get<int>();
accounts.push_back(accountsStruct);
}
}
As Accounts is child of MySQLTable
I would like to add all the data from std::vector<AccountsStruct> accounts into Data vector inherited from MySQlTable.
Also after that I would like to cycle thru the vector Data as it
is of type Accounts instead of MySQLTable class. However I don't
know how can I achieve those two things.
Is it possible and how?
I would drop the type DataStruct, and make MySqlTable a template.
#include <string>
#include <vector>
#include <mysqlx/xdevapi.h>
#include <memory>
namespace Vibranium {
using mysqlx::Table;
using mysqlx::RowResult;
using mysqlx::Session;
class MySQLTableBase {
public:
MySQLTableBase();
virtual ~MySQLTableBase() = default;
Table getTable(Session& conn) const;
RowResult getAll(Session& conn) const;
int Index;
std::string tableName;
};
template <typename T>
class MySQLTable : public MySQLTableBase {
public:
virtual void LoadTable(RowResult& res) = 0;
T dataStruct; // What is this?
std::vector<T> Data; // You don't need vector of pointers
};
}
Then you define Account and Accounts as
#include <string>
#include "Database/MySQLTable.h"
namespace Vibranium{
struct Account{
int id;
std::string email;
std::string warTag;
int state;
std::string name;
std::string lastname;
std::string country;
int dob_month;
int dob_day;
int dob_year;
double balance;
std::string created_at;
std::string updated_at;
int account_role;
int rank;
int playerRole;
};
class Accounts : public MySQLTable<Account>{
public:
Accounts() = default;
void LoadTable(RowResult& res) override;
};
}
So, have fun with C++!
You don't have a vector in MySQLTable with name "Data". You have method (Data) returning vector of ... To implement your request you should create method (for example) void SetData(...).
You can't. You can cycle through vector of Data and cast (for example static_cast, or other) each element from Data to AccountStruct. WARNING! Wrong cast operation may cause undefined behavior, crashes, etc.!

How do I add a string to a vector (and subsequently display it)?

I am 4 hours-new to C++ and have hit a brick wall with string vectors. When trying to add multiple strings to a string vector, I keep erroring out. I'd like to use push_back.
I would also like to display this string vector, but I'm not sure how (I know how to display non-vectors). Given that I have not been able to add a string to a vector of strings, I did not attempt to display the vector of strings yet.
profile.hpp
#include <iostream>
#include <vector>
class Profile
{
private:
std::string name;
std::string city;
std::string country;
int age;
std::vector<std::string> hobbies;
public:
std::vector<std::string> add_hobbies(std::string new_hobbies);
};
profile.cpp
#include <iostream>
#include "profile.hpp"
Profile::Profile(std::string new_name, int new_age, std::string new_city, std::string new_country)
: name(new_name), age(new_age), city(new_city), country(new_country)
{}
void Profile::add_hobbies(std::string new_hobbies)
{
hobbies.push_back(new_hobbies);
}
app.cpp
#include <iostream>
#include "profile.hpp"
int main()
{
Profile sam("Sam Drakkila", 30, "New York", "USA");
sam.add_hobbies("Play golf", "Read books", "Eat tennis balls"); // This doesn't seem to work.
}
g++ app.cpp profile.cpp. Prints a massive log of errors.
You have the following problems in your code:
You have declared add_hobbies returns std::vector<std::string>,
but in definition you have returned void. Presumably, you should have declared as a void function as it seems to be a setter function.
Secondly, you are passing a number of strings instead of a single string which
you defined here:
void Profile::add_hobbies(std::string new_hobbies) //>>> as per defenition, only one string can be passed!
// ^^^^^^^^^^^^^^^^^^^^^^^^
If you want to pass an arbitrary number of strings, you could usestd::initializer_list<std::string> instead.
Thirdly, you are missing the constructor declaration in the header file. Add
in the definition of class profile.hpp
Profile(std::string new_name, int new_age, std::string new_city, std::string new_country);
Last but not least, you need to include the <string> header in
order to use std::string(credits #πάντα ῥεῖ)
That means, (See live online)
#include <iostream>
#include <vector>
#include <string> // std::string
#include <initializer_list> // std::initializer_list
class Profile
{
private:
// ... other members
std::vector<std::string> hobbies;
public:
// ... other member functions
void add_hobbies(std::initializer_list<std::string> new_hobbies)
//^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
hobbies.reserve(hobbies.size() + new_hobbies.size()); // reserve memory to avoid, unwanted reallocations
for (const auto& hobby : new_hobbies) hobbies.emplace_back(hobby);
}
};
int main()
{
Profile sam{};
sam.add_hobbies({ "Play golf", "Read books", "Eat tennis balls" }); // now works
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
Alternatively using variadic templates and c++17 feature fold expression.
(See live online)
#include <iostream>
#include <vector>
#include <string> // std::string
#include <type_traits> // std::enable_if, std::is_same, std::common_type
using namespace std::literals;
class Profile
{
private:
// ... other members
std::vector<std::string> hobbies;
public:
// ... other member functions
template<typename... Args> // sfinae to restrict the Args type to be only std::string s
std::enable_if_t<std::is_same_v<std::common_type_t<Args...>, std::string>>
add_hobbies(Args&& ... args)
{
hobbies.reserve(hobbies.size() + sizeof...(Args));
(hobbies.emplace_back(std::forward<Args>(args)), ...);
}
};
int main()
{
Profile sam{};
sam.add_hobbies("Play golf"s, "Read books"s, "Eat tennis balls"s); // now works
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
You declare add_hobbies as returning a vector in your class declaration.
There are a few errors in your code:
Missing constructor declaration:
Profile(std::string new_name, int new_age, std::string new_city, std::string new_country);
Mismatch between return type of the declaration and definition of add_hobbies, should be void (since you're not returning anything).
void Profile::add_hobbies(std::string new_hobbies) { // ... }
You're also trying to pass 3 of them, while the function only has 1 parameter:
void add_hobbies(std::string const& h1, std::string const& h2, std::string const& h3);
// ...
void Profile::add_hobbies(std::string const& h1, std::string const& h2, std::string const& h3) {
hobbies.push_back(h1);
hobbies.push_back(h2);
hobbies.push_back(h3);
}

How to create a Primary Key in a dynamic matrix

I don't know how to create a dynamic std::vector in which I want to allocate Usernames as PrimaryKeys, and each username would be a pointer to another dynamic vector containing structs that have the following information:
struct message{
int id;
char *msg;
const string time;
};
I attach an illustrative image in order to make it more clear:
Where the username vector is the Primary Key pointing to a vector of structs previously mentioned.
How could I define it?
Instead of using a vector of usernames I preferred to use map this will guarantee that the username remains unique.
#include <map>
#include <vector>
#include <string>
#include <iostream>
struct message{
int id;
char *msg;
const std::string time;
};
int main()
{
std::map<std::string,std::vector<message *> > data;
message message1,message2;
message1.id = 1;
message1.msg = "Hi";
message2.id = 2;
message2.msg = "Hello";
std::vector<message *> messages;
messages.push_back(&message1);
messages.push_back(&message2);
data["smith"] = messages;
std::cout << (data["smith"]).at(0)->msg << std::endl;
}

Cannot declare array of strings as class member

I could not declare an array of strings in my class. Below my class definition:
class myclass{
public:
int ima,imb,imc;
string luci_semaf[2]={"Rosso","Giallo","Verde"};
};
and my main file
#include <iostream>
#include <fstream>
#include "string.h"
#include <string>
using namespace std;
#include "mylib.h"
int main() {
return 0;
}
Why do I get the following warnings / error?
You have two problems: The first is that you can't initialize the array inline like that, you have to use a constructor initializer list. The second problem is that you attempt to initialize an array of two elements with three elements.
To initialize it do e.g.
class myclass{
public:
int ima,imb,imc;
std::array<std::string, 3> luci_semaf;
// Without C++11 support needed for `std::array`, use
// std::string luci_semaf[3];
// If the size might change during runtime use `std::vector` instead
myclass()
: ima(0), imb(0), imc(0), luci_semaf{{"Rosso","Giallo","Verde"}}
{}
};
You can not initialize data member.
You can write like this:
class myclass{
public:
myclass() {
luci_semaf[0] = "Rosso";
luci_semaf[1] = "Giallo";
luci_semaf[2] = "Verde";
}
private:
int ima,imb,imc;
string luci_semaf[3];
};
You can assign the values of the array in the Сonstructor
You're declaring an array of size 2 but providing 3 strings!
Try storing the elements in vector of strings, in c++ vectors are used more often.
class myclass{
public:
int ima,imb,imc;
std::vector<std::string> strings;
myclass() {
strings.push_back("blabla");
}
};

Incomplete type error when instantiating class

I have a vertex class that has an id and adjacency list as private members. The adjacency list is stored as a map. When I instantiate an object of this class I want to create an empty map. I am switching over from python to C++ and its proving harder than I thought. Here's the code for the class:
#include "vertex.h"
class Vertex {
char _id;
std::map<char, int> _adjList;
public:
void addNeighbor(Vertex, char neighbor, int weight);
std::vector<char> getConnections(Vertex);
char getId();
int getWeight(Vertex, char neighbor);
Vertex(char);
};
Vertex::Vertex(char id){
std::map<char, int> adjList;
_adjList = adjList;
_id = id;
}
void Vertex::addNeighbor(Vertex v, char neighbor, int weight){
v._adjList.insert(std::map<char, int>::value_type(neighbor, weight));
}
std::vector<char> Vertex::getConnections(Vertex v){
std::vector<char> ids;
for(std::map<char,int>::iterator it = v._adjList.begin(); it != v._adjList.end(); ++it) {
ids.push_back(it->first);
};
return ids;
}
char Vertex::getId(){
return _id;
}
int Vertex::getWeight(Vertex v, char neighbor){
return v._adjList[neighbor];
}
Now when I instantiate this in main
Vertex V('a');
The compiler throws an error that the variable has incomplete type Vertex. Any help is greatly appreciated. Basically I want to construct an object with an id and empty map that will hold the id and path weight to the adjacent node. I am doing this for learning purposes
My vertex.h has:
#ifndef __graphs__vertex__
#define __graphs__vertex__
#include <stdio.h>
#include <map>
#include <vector>
class Vertex;
#endif
and then in my main I include vertex.h
The definition of Vertex should be in header, not in cpp:
I fixed declaration of method to add const and remove parameter Vertax as you should use this value.
#ifndef graphs_vertex_h
#define graphs_vertex_h
#include <map>
#include <vector>
class Vertex {
char _id;
std::map<char, int> _adjList;
public:
explicit Vertex(char);
void addNeighbor(char neighbor, int weight);
std::vector<char> getConnections();
char getId() const;
int getWeight(char neighbor) const;
};
#endif