C++ Struct with default argument, optionally changeable in constructor - c++

Let's say I have the following struct.
struct vehicle
{
int price;
char* year;
char* type;
}
I would like to make a regular constructor for it, that would allow me to specify each member.
Nevertheless, I would like to set the member "type", as "car" by default, having only to specify the "type" in the constructor, in the not so often cases when the vehicle would not be a "car".

First of all, you didn't say it, but I sense a small misunderstanding: The difference between a struct and a class is just convention. Structs are classes in C++. The keywords struct and class can be used to declare a class and the only difference is the default access (in accordance with the common convention that structs have all public).
That out of the way, you can simply write two constructors (i am using std::string for strings, because I find c-strings extremely difficult to work with):
struct vehicle
{
int price;
std::string year;
std::string type;
vehicle(int p, const std::string& y, const std::string& t) : price(p),year(y),type(t) {}
vehicle(int p, const std::string& y) : price(p),year(y),type("car") {}
};
You can also use in class initializer (they came with C++11):
struct vehicle
{
int price;
std::string year;
std::string type{"car"};
vehicle(int p, const std::string& y, const std::string& t) : price(p),year(y),type(t) {}
vehicle(int p, const std::string& y) : price(p),year(y) {}
};
The initializer list on the constructor wins over the in class initializer, and in the second constructor the in class initializer is used.

Related

Explicitly initalize abstract base class constructor with value determined by parameter of derived class constructor

Within my vehicle base class, I have a private member variable, string type (for type of vehicle, ie car, motorbike, tricycle, etc).
#pragma once
using namespace std;
#include <string>
#include <iostream>
class vehicle {
public:
vehicle(string reg, string make, string model, int age, string type);
virtual ~vehicle() = default;
virtual double costPerDay() = 0;
protected:
int age;
int perDayCostCap(int costPD);
double penceToPounds(int pence);
private:
const string type;
string const reg, make, model;
};
One of the derived classes, bike, has a numberOfWheels variable which is to be passed into its constructor. I want to initialize the base class constructor with type bicycle or tricycle depending on the numberOfWheels.
I can not figure out how to achieve this, seeing as the base class constructor has to be initialized before the function body of the child class.
The following shows what I would like to achieve (though, I know this is not possible):
bike::bike(int engineCC, int numOfWheels, string reg, string make, string model, int age)
:engineCC(engineCC), numOfWheels(numOfWheels) {
string tricOrBic = (numOfWheels == 2) ? "bicicle" : "tricicle";
vehicle:reg=reg, make=make, model=model, age=age, type=tricOrBic;
};
Like this?
bike::bike(int engineCC, int numOfWheels, string reg, string make, string model, int age)
: vehicle(reg, make, model, age, numOfWheels == 2 ? "bicycle" : "tricycle")
, engineCC(engineCC)
, numOfWheels(numOfWheels)
{
}
This is normal programming, maybe you had some problem I'm not seeing.

C++ Declaring an inherited constructor?

I'm having difficulties in defining a constructor for a class that inherits the properties of another class
class Transportation {
public:
int ID;
string company;
string vehicleOperator;
Transportation(int,string,string) {
}
};
class SeaTransport: public Transportation {
public:
int portNumber;
SeaTransport(int)::Transportation(int,string,string) {
}
};
I'm having issues with line 18 (SeaTransport(int)::Transportation(int,string,string)).
The error I receive occurs at the pont where I declare Transportation.
As seen in the code, a class Transportation is the body class and class SeaTransport inherits the properies of Transportation.
Transportation::Transportation(int, std::string, std::string)
+2 overloads
type name is not allowed
This error occurs at the int
typedef std::__cxx11::basic_string std::string
type name is not allowed
and this final error occurs at both string variables.
It seems you mix together scoping and a constructor initializer list.
The double-colon operator :: is for scope, while a constructor followed by a single colon and a list of initializations is an initializer list.
You must declare the SeaTransport constructor to take all the arguments, including those for the parent class (assuming you want to pass them on to the base constructor):
SeaTransport(int port, int id, string company, string operator);
Then in the definition (implementation) of the constructor you "call" the parent constructor in the constructor initializer list:
SeaTransport(int port, int id, string company, string oper)
: Transport(id, company, oper), // "Call" the parent class constructor
portNumber(port) // Initialize the own members
{
}
As Mr Some Programmer Dude said, you've a Scope problem in your code,
I will try to answer for your second question which is, how to add featured variables on your constructor.
Same as what you did for the port attribute.
You can define before all your Attribute which is boatNumber as int boadNumber = 0 then, you'll overload your
constructor with boatNumber(num) after the initializer operator and int num before the initializer operator.
class Transportation {
public:
int ID;
string company;
string vehicleOperator;
Transportation(int,string,string) {
}
~Transportation(){}
};
class SeaTransport: public Transportation {
public:
int portNumber;
int boatNumber;
SeaTransport(int num, int port, int id, string company, string oper)
:Transportation(id, company, oper), boatNumber(num),portNumber(port) {}
~SeaTransport(){}
};
But, if you want to get things more specific, you can create another class which is derived from SeaTransport
And then you'll define the number of your boat and more other details, if you want.
I'll draw you an instance of it :
class Boat: public SeaTransport {
public:
int boatNumber;
Boat(int bNum,int num, int port, int id, string company, string oper):
SeaTransport( num, port, id, company, oper),boatNumber(bNum){}
~Boat(){}
};

Creating a class that can store a int, std::string or double in one member variable

I am having to create a class which has a member variable named m_Value which is of type std::string but is supposed to be able to accept input from a user either as a double, int or std::string.
Here is this Field.h:
class Field
{
public:
Field(std::string name, std::string value);
std::string GetName();
std::string GetValue();
void Print();
private:
std::string m_Name;
std::string m_Value;
};
There is another class which has a method to instantiate this class called Element:
class Element
{
public:
Element();
void Print();
Field* AddField(std::string fieldName, std::string fieldValue);
Field* GetField(std::string fieldName);
private:
std::vector<Field*> m_Fields;
};
What I am supposed to be able to do is allow the class method AddField() to be able to take in an int, double or std::string and have it stored in the field member variable. This would be an example scenario:
I have thought to add overloading methods for AddField but then how do I store that value since member variables have to be of one type?
There are basically two approaches:
Store it and convert it to a string
Use a tagged union.
The tagged union approach is probably cleaner. Before C++17 the tagged unions can be implemented with anonymous unions. With c++17 you can use variants.
Rule 182 of the C++ core guidelines has a nice example.

how to create a class from an identifier?

the title might be a bit misleading, but I want to give some instance of a class an instance of a different class through polymorphism. I think that may have been even more misleading so I'll give an example;
Say I have a class called Spell, that is a parent class to the class Firebolt. I want another class, say Character, to be able to have the spell, 'Firebolt', in an its memory without ever having to #include the files for 'Firebolt'.
Now, I can think of a way that prior games have done this before. By giving each spell (or whatever else specific class type) a static const string ID or name and in spell having some function that can access this ID/name and return a new Firebolt() if they are the same.
This sounds pretty good actually, the problem I'm having is I don't know how to code this. I'm not sure how I can access these ID's from the parent class, and I'm not sure how to make a virtual function that will actually return the correct Spell. Any help would be amazing. I'll also provide the actual class code I'm working with here in case it might help you guys to answer, or someone with a similar problem to solve it.
The parent class;
class Art {
std::string name;
int EPCost;
int castTime;
int AoESize;
public:
Art(std::string n, int cp, int ct, int as):name(n), EPCost(cp), castTime(ct), AoESize(as) {}
virtual ~Art() {}
static Art* findArt(std::string ID);
int getAoESize() {return AoESize;}
std::string getName() {return name;}
int getEPCost() {return EPCost;}
virtual int getBaseDamage() = 0;
};
The subclass;
class FireBolt:public Art {
static const std::string name;
static const int EPCost;
static const int castTime;
static const int AoESize;
static const std::string ID;
public:
FireBolt():Art(name, EPCost, castTime, AoESize) {}
~FireBolt() {}
int getBaseDamage();
};
All you need to do is make your FireBolt::ID public.
class FireBolt:public Art {
public:
static const std::string ID;
...
};
Art* Art::findArt(const std::string& ID)
{
if (ID == FireBolt::ID)
return new FireBolt(...);
...
}

Can constructor Initializer fields be called with class objects, c++

I have two classes, one "bank" and one "account". Account's constructor takes an int and a string. Bank is supposed to have two objects of type "account" in it. Is it possible to have the two "account" objects in the fields initializer list be allocated dynamically and not with static values?
Here is the code I have that allocates it statically
class Bank
{
public:
Bank():checkings( 500, "C"), saving( 300, "s"){} //predfined int and string
private:
Account checkings;
Account saving;
};
Is it possible to do this? I want the constuctor to have its fields allocated dynamically according to user input. I keep getting errors so I am unsure if my syntax is wrong.
class Bank
{
public:
Bank():checkings( int val, string s), saving( int val, string s){} //dynamic
private:
Account checkings;
Account saving;
};
Also, how do I call this type of constructor in the .cpp file?
You can't put declarations (like int val) in a member initializer, only expressions (which can be/include previously declared variables).
It looks like maybe you want:
class Bank
{
public:
Bank(int val, std::string s) : checkings(val, s), saving(val, s) {}
// ...
};
or:
class Bank
{
public:
Bank(int check_val, std::string check_s,
int sav_val, std::string sav_s) :
checking(check_val, check_s), saving(sav_val, sav_s) {}
// ...
};