Confusing with c++ object type - c++

While i was trying to put object type to same object type of array, I am not sure how to put this.
Drink *a = new Drink("Whole Milk", 2.50, NEAT);
c.drinkArray[c.drinkCount++] = a;
Can anyone help me?
I am from java so I am so confused.....

As said try to avoid "new" in C++, I also tend to avoid 'C' style arrays (unless there is a clear benefit). 'C' style arrays don't have length checks and you can easily run into problems with writing out of bounds of the array and you will have to do some extra checking yourself.
#include <string>
#include <vector>
// not really sure what NEAT is
// but at least it can be made typesafe like this
enum class DrinkAttribute
{
UNKNWON,
NEAT,
};
struct Drink
{
std::string name = "no drink";
double price = 0.0;
DrinkAttribute attribute = DrinkAttribute::UNKNWON;
};
// put array and size information together including checks
struct Drinks
{
void add(const Drink& drink)
{
if (number_of_drinks < max_number_of_drinks)
{
drinks[number_of_drinks] = drink;
number_of_drinks++;
}
else
{
// some error handling here
}
}
Drink& get(std::size_t n)
{
if (n < number_of_drinks)
{
return drinks[n];
}
else
{
// some error handling here
// and return a drink representing no drink
// so all control paths return a value
// note I would probably just throw a std::invalid_argument exception here
// but I consider exception handling to be out of the scope of the question.
return no_drink;
}
}
static const std::size_t max_number_of_drinks = 10;
Drink drinks[max_number_of_drinks];
Drink no_drink;
std::size_t number_of_drinks = 0;
};
void ShowDrinksWithVector()
{
// to make dynamic collections of something you're bettor of using std::vector
// instead of arrays. This way you reuse tested code!
std::vector<Drink> drinks;
// at a drink to the collection of drinks
// the 3 arguments passed to emplace_back are used
// to construct an object of type Drink
drinks.emplace_back("Whole Milk", 2.50, DrinkAttribute::NEAT);
}
void ShowDrinksWithArray()
{
// this way you will have to write memory access checking code yourself
// that's why you will end up with an extra class (or you have to resort
// to using global variables)
Drinks drinks;
drinks.add(Drink{ "Whole Milk", 2.50, DrinkAttribute::NEAT });
auto drink = drinks.get(0);
}
int main()
{
ShowDrinksWithVector();
ShowDrinksWithArray();
}

Related

c++ vector of pointers to vector of pointers ordering

I have two classes, each has a vector of pointers to Data. What I want to do is to assign pointers in the vector of the class Sample2 to pointers in the vector of the class Sample1.
The problem is that as I assign pointers in the second vector, the order in witch they are stored is that of the first vector. I would like to store them in the order of insertion.
Here is a minimal reproducible example of the code:
#include <iostream>
#include <vector>
using namespace std; //for sample purposes
// For simplicity, the data is just a string in this example.
using Data = string;
// In the real code there is a class with a certain vector as a member,
// but for this example we can reduce it to just the vector.
using Sample1 = vector<Data*>;
Class Sample2 — the problem is here
class Sample2 {
vector<Data*> autodromos2;
public:
vector<Data*>& getAutodromos() { return autodromos2; }
// ** This is the function with the problem. **
void addAutodromos2(vector<string>& arguments, vector<Data*>& autodromos)
{
for (Data* a : autodromos) {
for (string &s : arguments) {
if (s == *a) { // The real test is more complex.
getAutodromos().push_back(a);
break;
}
}
}
}
};
Main function (generate data and call addAutodromos2)
int main()
{
// Create the list of elements to add to a `Sample2`.
// Note that these are strings, not Data objects (in the real code).
vector<string> arguments { "fourth", "first", "third" };
// Create the `Sample1` data with which to work.
Sample1 s1 {
new Data("first"), new Data("second"), new Data("third"),
new Data("fourth"), new Data("fifth")
};
// Create the `Sample2` data from the list and `s1`.
Sample2 s2;
s2.addAutodromos2(arguments, s1);
// Diagnostic:
for (Data* a : s2.getAutodromos()) {
cout << *a << endl;
}
}
The output is
first
third
fourth
when it should be
fourth
first
third
Actually the sequence problem with loops in addAutodromos2() you need to change function with below code:
for (string s : arguments)
{
for (Data* a : autodromos)
{
if (s == *a) { // The real test is more complex.
getAutodromos().push_back(a);
break;
}
}
}
Switch the for-loops. output is fourth first third
Hope this will help.
There is a school of thought that says if you have nested loops inside a function, you probably are not thinking abstractly enough. While that might be an overstatement at times, it does have value in this situation. Let's look at the inner loop.
for (string s : arguments) {
if (s == *a) {
getAutodromos().push_back(a);
break;
}
}
This loop searches for *a in arguments and if found does something. The search is a concept that could be abstracted away into its own function, let's call it found, a function that returns a bool.
// Preliminary revision
void addAutodromos2(vector<string>& arguments, vector<Data*>& autodromos)
{
for (Data* a : autodromos) {
if ( found(arguments, *a) ) {
getAutodromos().push_back(a);
}
}
}
With only one loop to look at, it should be clearer what the problem is. Elements are added to getAutodromos() in the order they appear in autodromos. To use the order within arguments, you need to loop through it. (I'll change the name of the helper function to find_by_name and have it return either an iterator to the found element or the end iterator. A boolean return value is no longer adequate.)
// Final revision
void addAutodromos2(vector<string>& arguments, vector<Data*>& autodromos)
{
for (string s : arguments) {
auto result = find_by_name(autodromos, s);
if ( result != autodromos.end() ) {
getAutodromos().push_back(*result);
}
}
}
A missing piece here is the find_by_name function. The good news is that this task is so common, that functionality is part of the standard library, in the header <algorithm>. The bad news is that there is a bit of typing to use the library function, as the arguments are more complex (for greater flexibility). You may want to define a wrapper to specialize it to your case.
// Returns an iterator to the element with the indicated name, or
// autodromos.end() if not found.
static auto find_by_name(const vector<Data*> & autodromos, const string & name)
{
return std::find_if(autodromos.begin(), autodromos.end(), [&name](Data *a){
return name == *a; // or name == a->get_name(), when Data is more complex
});
}
Note that if the real test was as simple as comparing name == *a, then std::find could be used instead of std::find_if, and there would be no need to use a lambda.
Don't forget to #include <algorithm> earlier in the file.

Can class member arrays / std::arrays be replaced?

New to C++, looking to replicate some functionality available in C# involving replacing an object array member with a newly constructed array.
class Car {
int id;
Car() {}
};
class Garage {
Car cars[1];
Garage() {}
void addCars(Car crs[]) {
//...do update here
}
};
In C# I could do something like:
addCars(Car[] crs){
Car[] temp = new Car[cars.Length + crs.Length];
for(int i = 0; i < cars.length; i++){
temp[i] = cars[i];
}
for(int i = 0; i < crs.Length; i++){
temp[i + cars.Length] = crs[i];
}
cars = temp;
}
Or Array.Resize, Array.Copy.
Can I declare an array and replace an existing object instance member array?
If this isn't possible: How practical are arrays in C++? I can see something like Excel utilising them (if they aren't modifiable) but it seems like it would be really limited. I can see why memory allocation might constrain this but obviously I'm from the easier side of the C fence.
Thanks.
As an example, here would be some sort of C++ equivalent to your example. It probably has some vague semblance to the C# equivalent.
#include <initializer_list>
#include <iostream>
#include <ostream>
#include <vector>
using std::vector;
using std::cout;
using std::endl;
using std::ostream;
using std::initializer_list;
struct Car {
int id;
Car(int newId) : id{newId} {}
};
ostream& operator<<(ostream& o, Car const& car) {
o << car.id;
return o;
}
struct Garage {
vector<Car> cars;
Garage() {}
void addCars(initializer_list<Car> l) {
cars.insert(cars.end(), l.begin(), l.end());
}
};
ostream& operator<<(ostream& o, Garage const& garage) {
char const* sep = "";
for (auto const& car : garage.cars) {
o << sep << car;
sep = ", ";
}
return o;
}
int main() {
Garage garage;
garage.addCars({7, 8, 99, 1000});
cout << garage << endl;
return 0;
}
Can I declare an array and replace an existing object instance member array?
No, std::array and type[] array sizes are known at compile time. If the new array has the same size as the existing array, a copy is needed (via e.g., memcpy)
You could theoretically use a pointer instead, e.g.
Car cars* = nullptr;
// ...
cars = new Car[size];
// ...
delete[] cars;
However, this puts the burden of memory tracking on you (I had to manually call delete[]). Instead, use a std::vector, which wraps up all that logic for you.
std::vector<Car> cars;
Car c;
// ...
cars.push_back(c);
How practical are arrays in C++?
Quite practical. A lot of high performance computing relies on arrays whose sizes are known at compile time for performance reasons.
The C++ arrays and std::array are fixed size at compile time. Their size can't change at runtime. You can copy an std::array onto another std::array ("replace"). But you can't do so for the C++ build-in arrays: these need to be copied element by element for example with std::copy().
If you need to dynamically resize your container, you should consider std::vector instead. These are much more flexible. And you can of course copy or move them as a whole.

Deleting an element in a vector by value

How can I retrieve an object from the Flight to be compared to the input (flightNumber) in the main? How do I declare the attributes type in the main?
When I compile, a error message is displayed: invalid conversion of 'int' to '*Flight*' at agent1.delete(flightNumber);.
class Flight
{
int FlightNumber
};
class TravelAgent
{
vector <Flight *> flightList;
};
void Agent::delete(Flight *obj)
{
vector<Flight*>::iterator ptr;
for(ptr=flightList.begin();ptr!=flightList.end();ptr++)
{
if((*Ptr)==obj)
{
flightList.erase(ptr);
break;
}
}
if ((ptr) == flightList.end())
{
cout<<"Flight not found"<<endl;
}
}
int main
{
Agent agent1;
int flightNumber;
cout<<"Enter the number of the flight: "<<flush;
in>>flightNumber;
agent1.delete(flightNumber);
}
You can add(if not present) a getter in Flight class
class Flight{
int FlightNumber;
public:
int getflightNumber(){ return flightNumber;}
};
and go as following:-
void Agent::delete(int flightNumber)
{
vector<Flight*>::iterator ptr;
for(ptr=flightList.begin();ptr!=flightList.end();ptr++)
{
if(((*Ptr)->getflightNumber() == flightNumber)
{
flightList.erase(ptr);
break;
}
}
if ((fPtr) == listFlight.end())
{
cout<<"Flight not found"<<endl;
}
}
Since the code here isn't fully functional, it's hard to give you good advice.
First, your error happens because you call (what seems to be) the member function, void Agent::delete(Flight *obj), with a variable of type int instead of type Flight. The compiler is not able to interpret your Flight object as an int, so it throws an error.
Secondly, you want to know how to retrieve attributes from an object. I will advise you to have a look to accessors and mutators.
If you want to retrieve information hold in your Flight object, you should expose member functions allowing that.
// in your header file
class Flight
{
private:
int flight_number;
public:
// retrieve flight number value
int get_flight_number(void) const;
// allow to set the flight number value
void set_flight_number(int new_flight_number);
// some other member functions
}
// in your source file
int Flight::get_flight_number(void) const
{
return this->flight_number;
}
void Flight::set_flight_number(int new_flight_number)
{
// let's do some verification (do whatever you want)
if (new_flight_number > 0)
{
this->flight_number = new_flight_number;
}
}
This way you will be able to set and access your flight_number by writing, for example :
void test_function(Flight *f)
{
if (f->get_flight_number() == 42)
{
// do some stuff
}
}
int main()
{
Flight *my_f = new Flight();
my_f->set_flight_number = 4242;
my_test_function(my_f);
}
Now, you have enough information to get going.
NOTES :
You heavily use pointers. Modern C++ strongly tends to not! Try to use references or move operation. You can consult this pages for info:
cpp-reference - references
cpp-reference - move semantics
It's a bit hardcore for beginner though. The web is full of great article. about it
You original error is in your main method. You need to change it so that instead of passing the flight number to your delete method, you create an instance of your Flight class.
int main() { // you are also missing parenthesis
Agent agent1;
int flightNumber;
cout<<"Enter the number of the flight: "<<flush; // I don't know what flush is but maybe you meant std::endl
cin>>flightNumber;
Flight flight(flightNumber);
agent1.delete(&flight); // delete takes a Flight* not an int
}
This requires that your Flight class have an appropriate constructor.
class Flight
{
public:
Flight(int flightNumber)
: flightNumber_(flightNumber)
{}
private:
int flightNumber_;
};
Then in your delete method you search your vector for the Flight instance that has the same flightNumber_ as the Flight you want to remove from your vector. This will require your Flight class to have some way of returning it's flightNumber_ member variable.
This is definitely NOT the best way to do this and is far from being in accordance with modern C++ standards but it should get you going.

Calling a constructor in C++

I am just starting out with C++. I have a class ourVector and within that class I have a constructor that is named ourVector() as well and it includes the initializations of variables. I need these variables to reset with every loop in main, but I can't figure out how to call the constructor in main.
class ourVector
ourVector()
{
vectorCap = 20;
vectorSize = 0;
}
In main my class object is called ourVector vectorTest;
I just would like to figure out how to call ourVector() without getting an error so I can place it at the end of my loop in main to clear and re-initialize the variables.
Any help would be greatly appreciated.
Thank you!
Usually when you find yourself doing things like this it's a sign that maybe there's a more semantically appropriate way to structure your code (i.e. make the code structure more closely represent your intent).
In your case, ask yourself why you need to reset the value every time through the loop. It seems like you are just using your object to hold some intermediate data on each iteration through the loop, and you aren't concerned about the values outside of the loop (but if you are, you want something like riderBill's answer). So really, your ourVector instance is only useful within the scope of that loop.
So make your code structure reflect that:
int main () {
...
while (...) { // <- this represents your loop
ourVector v; // <- each time through, 'v' is constructed
... // <- do whatever with 'v' here
} // <- that 'v' goes away when it goes out of scope
...
}
In other words, just declare it in the loop, where it belongs. Semantically this makes sense (it represents how and where you're actually using the object), and it does what you want without modification to your ourVector.
In general, as a beginner's rule of thumb, try to declare variables in the tightest scope possible that still works for your code.
The constructor is only called when instantiating an object; you cannot explicitly call it to reinitialize your variables. But you can call public member setter function(s) from the constructor. Then you can call the setter function(s) again from within your loop.
class ourVector
{ int vectorCap ;
int const defaultVectorCap = 20; // No magic numbers!
int vectorSize ;
int const defaultVectorSize = 0;
int roomToGrow ; // To illustrate a point about setters.
public:
// Constructors
ourVector() // Use this constructor if you don't know the proper initial values
// (you probably always do or never do).
{ setVectorCap (defaultVectorCap );
setVectorSize(defaultVectorSize);
} // End of default constructor
ourVector( int vecCap, int vecSize) // Lining stuff up improves readability
{ setVectorCap (vecCap ); // (e.g. understanding the code and
setVectorSize( vecSize ); // spotting errors easily).
// It has helped me spot and avoid
// bugs and saved me many many hours.
// Horizontal white space is cheap!
// --Not so forvertical white space IMHO.
// Setters
void setVectorCap(int vecCap)
{ vectorCap = vecCap;
// I might need this internally in the class.
// Setters can do more than just set a single value.
roomToGrow = vectorCap - vectorSize;
} // End of setVector w/ parameter
void setVectorSize(int vecSize)
{ vectorSize = vecSize;
roomToGrow = vectorCap - vectorSize; // Ok, redundant code. But I did say
// "As much as practical...."
} // End of setVectorCap w/ parameter
void setVectorSize() // Set to default
{ // Don't just set it here--leads to poor maintainability, i.e. future bugs.
// As much as practical, redundant code should be avoided.
// Call the setter that takes the parameter instead.
setVectorSize(defaultVectorSize);
} // End of setVectorSize for default size
void setVectorCap() // Set to default
{ setVectorCap (defaultVectorCap );
} // End of setVectorCap for default size
}; // End of class ourVector
#include <cstdio>
#include <cstdlib>
#include "ourVector.hpp"
int main(int argc, char *argv[]);
void doSomething(ourVector oV );
int main(int argc, char *argv[])
{ ourVector oV;
// Or, if you want non-default values,
//int mySize = 2;
//int myCap = 30;
//ourVector(mySize, myCap);
for (int i = 0; i<10; i++)
{ // Set fields to original size.
oV.setVectorSize();
oV.setVectorCap ();
// Or
//oV.setVectorSize(mySize);
//oV.setVectorCap (myCap );
// Whatever it is your are doing
// ...
}
// Do whatever with your vector. If you don't need it anymore, you probably should
// have instantiated it inside the for() block (unless the constructor is
// computationally expensive).
doSomething(oV);
return 0;
} // End of main()
void doSomething(ourVector oV) {}
This code works:
class ourVector
{
public:
ourVector() : vectorCap(20), vectorSize(0) { };
ourVector(int c, int s) : vectorCap(c), vectorSize(s) { };
void setVCap(int v)
{
vectorCap = v;
}
void setVSize(int v)
{
vectorSize = v;
}
int getVCap()
{
return vectorCap;
}
int getVSize()
{
return vectorSize;
}
void print()
{
std::cout << vectorCap << ' ' << vectorSize << '\n';
}
private:
int vectorCap;
int vectorSize;
};
int main()
{
ourVector vectorTest(5,5);
vectorTest.print();
vectorTest.setVCap(6);
vectorTest.setVSize(6);
vectorTest.print();
std::cout << vectorTest.getVCap() << ' ' << vectorTest.getVSize() << '\n';
vectorTest = ourVector();
vectorTest.print();
}
The ourVector() : vectorCap(value), vectorSize(value) { }; parts are the initializers. The vectorCap(value) part sets vectorCap to value; the { } section is an empty method, use this to do any calculations and verifications you need. The SetVCap(int) and SetVSize(int) methods can be called to change the values of vectorCap and vectorSize, respectively. getVCap() and getVSize() return the values of vectorCap and vectorSize respectively.
In my example, you do not need to validate the code, so the initializers ourVector() : vectorCap(value), vectorSize(value) { }; work perfectly fine. If you need to validate the input, you may wish to call the assignment functions from the initializer so you only need to implement the validation once, which makes debugging easier. To do this, just replace the constructors with these constructors. Now you need only validate the input in one place:
ourVector()
{
setVCap(20);
setVSize(0);
}
ourVector(int c, int s)
{
setVCap(c);
setVSize(s);
}

C++ - Return multidimensional array from function

I am writing a code for Cellular Automata and I need an evolution function to calculate the state of the automata after a time step.
I choose to call this function evol, to test it I created an elementary function in C++. Unfortunately it does not compile since the compiler cannot understand that I need it to return an array. Here is the code :
#include <iostream>
#include <cmath>
#include <vector>
#include <string>
using namespace std;
const int N = 51; // Size of the grid; two columns/rows are added at the beginning and the end of the array (no evolution of the CA on the boundaries)
class Cell{
//defining whats a cell here
};
void showCA(Cell CA[N+2][N+2]){
//function to print the CA grid in the terminal
}
Cell[N+2][N+2] evol(Cell CA[N+2][N+2]){
return CA;
}
int main()
{
// Initialisation
cout << "Initialisation" << endl;
static Cell CA[N+2][N+2];
// some code here to initialize properly the Cell array.
showCA(CA);
CA = evol(CA);
showCA(CA);
return 0;
}
The compiler returns this error :
error: expected unqualified-id
Cell[N+2][N+2] evol(Cell CA[N+2][N+2]){
Any idea on how I should implement this ?
You cannot return arrays from functions:
§ 8.3.5/8
Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things.
If you are wishing to return raw, C-style arrays from functions, then you have to use a reference or pointer. For example, here's how it is done using a reference (you can do the same using a pointer by replacing & with *):
Cell (&evol(Cell (&CA)[N+2][N+2]))[N+2][N+2];
However, this is very unintuitive and hard to read. If your compiler supports the latest standard (C++11) the return type can be cleaned up using a trailing return type:
auto evol(Cell (&CA)[N+2][N+2]) -> Cell(&)[N+2][N+2];
But again, this is probably still harder to read.
C++11 facilitates the handling of C-style arrays with the container std::array<>. Non-C++11 code should use std::vector<>:
using Cells = std::array<std::array<Cell, N+2>, N+2>;
Cells const& evol(Cells const& CA);
You can use
typedef std::vector<std::vector<Cell>> CellArray;
CellArray Cells(N+2); // resize main dimension
for (size_t i=0; i<N+2; i++)
Cells[i].resize(N+2); // resize all cells of main dimension
to hold your cell array, but you also need to add a copy constructor and operator= in Cell class
class Cell {
public:
Cell() { ... default ctor code here ... }
Cell(const Cell &c) { *this = c; }
Cell &operator=(const Cell&c)
{
if (this != &c)
{
... copy data from c members to this members here ...
}
return *this;
}
};
Your evol function then can return a CellArray:
CellArray evol(CellArray &c)
{
CellArray r;
... do some calculations with c and r ...
return r;
}
once you have declared a variable using the array syntax like you have:
Cell CA[N+2][N+2];
you cannot assign CA to be something else. You can only assign values to its contents. Hence,
CA = evol(CA);
is wrong.
You can do the following:
Cell (*CA2)[N+2] = evol(CA);
As the number of elements seems to be fixed, I suggest you use the std::array container:
const int N = 51;
typedef std::array<std::array<Cell,N+2>, N+2> datatype;
You can then use this type as a return type:
datatype Evol( const datatype& d );
You can access elements just as if it was a "C" array:
datatype d;
Cell c;
d[10][20] = c;
I would strongly suggest encapsulate your array into a class. You cannot return an array, but you can return an object that contains an array.