Is there a method I can use to be able to declare a new object w/ inherited variables with a single line of code? Example:
#include <iostream>
using namespace std;
struct item_t {
string name;
string desc;
double weight;
};
struct hat_t : item_t
{
string material;
double size;
};
int main ()
{
hat_t fedora; // declaring individually works fine
fedora.name = "Fedora";
fedora.size = 7.5;
// this is also OK
item_t hammer = {"Hammer", "Used to hit things", 6.25};
// this is NOT OK - is there a way to make this work?
hat_t cowboy = {"Cowboy Hat", "10 gallon hat", 4.5, "straw", 6.5};
return 0;
}
Classes with inheritance are not POD and therefore are definitely not aggregates. If you are not using virtual functions, prefer composition to inheritance.
struct item_t {
string name;
string desc;
double weight;
};
struct hat_t
{
item_t item;
string material;
double size;
};
int main ()
{
// this is also OK
item_t hammer = {"Hammer", "Used to hit things", 6.25};
// this is now valid
hat_t cowboy = {"Cowboy Hat", "10 gallon hat", 4.5, "straw", 6.5};
return 0;
}
I believe having base classes prevents the aggregate initialization syntax in C++03. C++0x has more general initialization using braces, and so it is more likely to work there.
Can you maybe just use a constructor?
struct item_t {
item_t(string nameInput, string descInput, double weightInput):
name(nameInput),
desc(descInput),
weight(weightInput)
{}
string name;
string desc;
double weight;
};
struct hat_t : item_t
{
hat_t(string materinInput,d double sizeInput string nameInput, string descInput, double weightInput) :
material(materialInput), size(size), item_t(nameInput, descInput, weightInput)
{}
string material;
double size;
};
then you can just call the constructor you want.
Related
I have created 3 classes: Auto (means "car"), Klant (means "customer") and AutoVerhuur (means "car dealership).
In my main(), I have created Auto and Klant objects, and am trying to create an AutoVerhuur object.
In this last class, I basically want to reference to a specifc Klant and Auto (which customer rented which car). But, when I try that, I get an error:
error: no matching function for call to 'Auto::Auto()'
How do I correctly reference other objects in my object?
Here is my code, if you want to take a look:
#include <iostream>
using namespace std;
class Auto{
private:
string type;
double prijs_per_dag;
public:
Auto(string type, double prijs_per_dag){
this->type = type;
this->prijs_per_dag = prijs_per_dag;
}
void set_prijs_per_dag(double percentage){
this->prijs_per_dag = percentage;
}
double get_prijs_per_dag(){
return prijs_per_dag;
}
};
class Klant{
private:
string naam;
double korting_percentage;
public:
Klant(string naam):
naam(naam){}
void set_korting(double percentage){
this->korting_percentage = percentage;
}
double get_korting(){
return this->korting_percentage;
}
string get_name(){
return naam;
}
void set_name(string naam){
this->naam = naam;
}
};
class AutoHuur{
private:
int aantal_dagen;
Auto wagen;
Klant huur;
public:
AutoHuur(Auto car, Klant huurder, int dagen){
wagen = car;
huur = huurder;
aantal_dagen = dagen;
}
};
int main(){
Klant k("Mijnheer de Vries");
k.set_korting(10.0);
Auto a1("Peugeot 207", 50);
AutoHuur ah1(a1, k, 4);
}
Your Auto class does not have a default constructor defined, but your AutoHuur class has an Auto wagen; data member which the compiler is trying to default-construct (because you haven't told it otherwise), hence the error.
So, you need to either:
give the Auto class a default constructor, eg:
Auto(){
this->type = "";
this->prijs_per_dag = 0;
// or whatever default values make sense for your needs...
}
Otherwise, change the constructor of the AutoHuur class to use its member initialization list to construct the wagen member using the desired Auto constructor (you should do the same for the other data members, too), eg:
AutoHuur(Auto car, Klant huurder, int dagen)
: wagen(car), huur(huurder), aantal_dagen(dagen)
{
}
I have recently started learning OOP in C++ and I started solving example tasks regarding it. I want to instantiate an object of the class CStudent after having created a default constructor for it. However the compiler cannot compile the code. I would like to ask why is that?
When you write inside your class:
CStudent();
CStudent(string name, string fn);
...you only declare two constructors, one default (taking no-argument) and one taking two strings.
After declaring them, you need to define them, the same way you defined the methods getName or getAverage:
// Outside of the declaration of the class
CStudent::CStudent() { }
// Use member initializer list if you can
CStudent::CStudent(std::string name, string fn) :
name(std::move(name)), fn(std::move(fn)) { }
In C++, you can also define these when declaring them inside the class:
class CStudent {
// ...
public:
CStudent() { }
CStudent(std::string name, string fn) :
name(std::move(name)), fn(std::move(fn)) { }
// ...
};
Since C++11, you can let the compiler generate the default constructor for you:
// Inside the class declaration
CStudent() = default;
This should work, As commented by Holt, You need to define constructor, You have just declared it.
#include <iostream>
#include <string>
#include <list>
using namespace std;
class CStudent {
string name = "Steve";
list<int> scores;
string fn;
public:
CStudent() {};
CStudent(string name, string fn);
string getName();
double getAverage();
void addScore(int);
};
string CStudent::getName() {
return name;
}
double CStudent::getAverage() {
int av = 0;
for (auto x = scores.begin(); x != scores.end(); x++) {
av += *x;
}
return av / scores.size();
}
void CStudent::addScore(int sc) {
scores.push_back(sc);
}
int main()
{
CStudent stud1;
cout<< stud1.getName()<< endl;
return 0;
}
I have a little example.
Im trying to add data to my std::vector from a class that is not in the same namespace.
both classes are the same.
How can i push data to to vector from a class that is not in same namespace
class A
{
public:
std::string name;
int32_t Size;
};
namespace TEST {
class A
{
public:
std::string name;
int32_t Size;
};
class File
{
public:
std::vector<A> data;
};
}
int main()
{
A data = { "outside namespace", 10 };
TEST::File file;
file.data.push_back(data);
return 0;
}
I guess you need an extra constructor in TEST::A for copying members from global A:
namespace TEST {
class A
{
public:
A(const ::A& a) :
name(a.name),
Size(a.Size)
{}
std::string name;
int32_t Size;
};
...
When pushing to vector do it like this:
int main()
{
A data = { "outside namespace", 10 };
TEST::File file;
file.data.push_back(TEST::A(data));
return 0;
}
How can i push data to to vector from a class that is not in same
namespace
The problem isnt really different namespaces, but the problem is that A and TEST::A are two different classes and you cannot push an A into a vector of TEST::As.
Just qualify the names with the namespace name:
TEST::A data = { "outside namespace", 10 };
A and TEST::A are two different classes.
You declare your vector to accept objects from the relevant class in its namespace:
std::vector<A> v; // will accept objects of class A
std::vector<TEST::A> v; // will accept objects of class TEST::A
I want to compare the object type of a child class which inherits from a parent class and is stored in a vector of parent class as below:
#include <string>
#include <iostream>
#include <vector>
#include <typeinfo>
using namespace std;
class Agent{
public:
Agent(string nam){ name = nam; }
~Agent();
protected:
string name;
};
class Human :public Agent{
public:
Human(string nam, int a):Agent(nam){ age = a; }
~Human();
protected:
int age;
};
int main(){
vector<Agent*> agents;
Agent* agent=new Agent("ask");
Human* human=new Human("ask2",18);
Agent* agent2=new Human("AgentAsk",20);
agents.push_back(agent);
agents.push_back(human);
agents.push_back(agent2);
cout << (typeid(agents[1]) == typeid(Agent*)) << endl; /// True
cout << (typeid(agents[1]) == typeid(Human*)) << endl; /// I expect it to be true but its false
cout << (typeid(agents[1]) != typeid(Agent*)) << endl; /// False
return 0;
}
I need help to obtain the proper result.
I searched for it but could not find a proper solution and explanation.
Please, try to explain your code as much as possible.
You can use type traits for your classes, but if you need a simple (quick and dirty, maybe) solution, you may do it as follows:
#include <string>
#include <iostream>
#include <vector>
#include <typeinfo>
using namespace std;
class Agent{
public:
static const string TYPE;
explicit Agent(const string& nam) : name(nam) {}
virtual ~Agent(){}
virtual string type() const {
return TYPE;
}
protected:
string name;
};
const string Agent::TYPE = "Agent";
class Human :public Agent {
public:
static const string TYPE;
Human(const string& nam, int a):Agent(nam), age(a) {}
~Human(){}
virtual string type() const {
return TYPE;
}
protected:
int age;
};
const string Human::TYPE = "Human";
int main(){
vector<Agent*> agents;
Agent* agent=new Agent("ask");
Human* human=new Human("ask2",18);
Agent* agent2=new Human("AgentAsk",20);
agents.push_back(agent);
agents.push_back(human);
agents.push_back(agent2);
for(auto agent : agents) {
cout << agent->type() << " ";
cout << boolalpha << (agent->type() == Agent::TYPE) << endl;
}
//free up memory allocated using new
// or just use smart pointers
return 0;
}
It's better to define an abstract class and move the abstraction (like type() method) up and other details down to the derived classes.
Here is a possible approach to differentiate the types in a hierarchy at runtime (comments in the code, as requested by the OP):
#include<vector>
#include<cassert>
// This is a simple class that acts as a counter
struct Cnt {
static int cnt;
};
int Cnt::cnt = 0;
// A template class helps us to differentiate
// the types and to give them a set of values
// that identify the actual types at runtime
template<typename T>
struct Type: private Cnt {
static const int type;
};
template<typename T>
const int Type<T>::type = Cnt::cnt++;
// The Agent offers a virtual method that
// returns a numeric identifier of the type.
// The above mentioned classes are used
// to generate an unique value for this type.
class Agent {
public:
virtual int type() const {
return Type<Agent>::type;
}
};
// If you want Human to have its own
// numeric identifier, you can simply override
// the inherited method and return a different
// type.
// Using the Type class is still the right
// solution. It assures that the returned type
// won't collide with the ones generated so
// far.
class Human: public Agent {
public:
int type() const override {
return Type<Human>::type;
}
};
int main() {
std::vector<Agent*> vec;
vec.push_back(new Agent);
vec.push_back(new Human);
assert(vec[0]->type() == Type<Agent>::type);
assert(vec[0]->type() != Type<Human>::type);
assert(vec[1]->type() == Type<Human>::type);
assert(vec[1]->type() != Type<Agent>::type);
}
It's pretty invasive, but this way you can also decide not to give a different type to a child if you want.
A note on typeid.
From here you can find that:
There is no guarantee that the sameĀ std::type_info instance will be referred to by all evaluations of the typeid expression on the same type
You wouldn't have had guarantees even if working with different types. Anyway, you are using the typeof operator each time on the same type.
You created a vector of Agent*, so (typeid(agents[1]) == typeid(Human*)) is false because agents[1] is an Agent, not a Human.
I want to declare a struct within a class which is private and I want to give a character value to a variable in the same struct, but I can't initialize it or cin it:
class puple
{
private:
struct p
{
char name[25];
int grade;
};
public:
puple(){};
void setme()
{
this->p::grade=99;
this->p::name[25]='g'; //here is the problem
}
void printme()
{
cout<<"Name: "<<this->p::name<<endl;
cout<<"Grade: "<<this->p::grade<<endl;
}
};
void main()
{
puple pu1;
pu1.setme();
pu1.printme();
}
You've describe a type called "p" which is a struct. There is yet no thing of type p around. Therefore your
p->...
calls make no sense.
Try declaring
p pInstance;
in your class and using it, ie:
void setme()
{
this->pInstance.grade=99;
this->pInstance.name[25]='g'; //here is the problem
}
Note even with this your assignment to name[25] will fail as the allowed indices for that array are 0 up to 24 (totalling 25 elements).
You have two serious problems here
struct p
{
char name[25];
int grade;
};
This defines a struct type, named p. I think what you wanted to do was
struct
{
char name[25];
int grade;
} p;
This will declare a struct, named p, with the name and grade member variables.
Your second serious problem is that you assign:
this->p::name[25]='g'; //here is the problem
This assigns 'g' to the 26th element of the array name. (arrays are 0-indexed)
isn't it
struct { ... } p; // variable of struct-type definition.
not
struct p { ... }; // type 'struct p' definition.
?
Place the struct definition outside of the class using a typedef. By having the struct defined in your .cpp file it will not be visible outside of your class.
#include <iostream>
typedef struct _foo
{
int a;
} foo;
class bar
{
public:
void setA(int newa);
int getA();
private:
foo myfoo;
};
void bar::setA(int newa)
{
myfoo.a = newa;
}
int bar::getA()
{
return myfoo.a;
}
using namespace std;
int main()
{
bar mybar;
mybar.setA(17);
cout << mybar.getA() << endl;
return 0;
}