I want to use the C++ preprocessor to be able to write the following in any C++ block.
class Student {
private:
int age;
int grade;
int courses;
}
int main(){
CREATE_STUDENT 15+62+2 ;
}
The previous code will create a Student with these 3 members.
I want to use + operator overloading.
Any idea of how to do it?
I want EXACTLY the syntax I mentioned above.
Why not just use a constructor:
class Student {
private:
int age;
int grade;
int courses;
public:
Student(int a, int g, int c)
{
age = a;
grade = g;
courses = c;
}
}
int main(){
Student s(15,62,2);
}
Well, I completely fail to understand why you would want to do such a thing. But it is possible, sorta.
You'll need to make it a bit more complex than that to be able to use more than one such "construct" in the same block though.
#include <iostream>
#define GRADE_STUDENT Student student = (Student)
class Student {
public:
Student(int a): age(a), grade(-1), courses(-1), setup(0) {};
Student& operator+(int p)
{
switch(setup) {
case 0: grade = p; break;
case 1: courses = p; break;
default: /* die */ char *p=0; *p=0;
}
setup++;
return *this;
};
void print()
{
std::cout << age << ", " << grade << ", " << courses << std::endl;
};
private:
int age;
int grade;
int courses;
int setup;
};
int main()
{
{
GRADE_STUDENT 15+62+2 ;
student.print();
}
{
GRADE_STUDENT 15+62 ;
student.print();
}
{
GRADE_STUDENT 15+62+2+3 ; // crash
}
return 42;
}
You should template your class instead of working with the preprocessor.
Related
I am trying to write an overloaded operator= to assign copy the content of an object studentA to studentB. After compiling, it just crashes and as usual "stops working".
#include <cstdlib>
#include <iostream>
using namespace std;
class STUDENT {
public:
string ID;
string name;
unsigned int birthyear;
STUDENT(string x, string y, unsigned int z) {
ID = x;
name = y;
birthyear = z;
};
STUDENT operator = (STUDENT const &obj) {
STUDENT *res;
*res = obj;
return *res;
}
void print() {
cout << ID << " " << name << " " << birthyear;
}
};
int main() {
STUDENT studentA("1951049", "Nguyen Vinh Hao", 2001);
STUDENT studentB("1951050", "Nguyen Van Hao", 1999);
studentB = studentA;
studentB.print();
return 0;
}
I think there are some problems with the pointer *res, but I don't really know what they are. I hope you can help me.
Your operator= is implemented all wrong. Your res pointer does not point anywhere meaningful when you dereference and assign to it. That is why your code is crashing.
You need to actually copy the individual members yourself from obj to *this, similarly to how you are doing so in your constructor, eg:
#include <iostream>
using namespace std;
class STUDENT {
public:
string ID;
string name;
unsigned int birthyear;
STUDENT(string x, string y, unsigned int z) {
ID = x;
name = y;
birthyear = z;
}
STUDENT& operator=(STUDENT const &obj) {
ID = obj.ID;
name = obj.name;
birthyear = obj.birthyear;
return *this;
}
void print() const {
cout << ID << " " << name << " " << birthyear;
}
};
int main() {
STUDENT studentA("1951049", "Nguyen Vinh Hao", 2001);
STUDENT studentB("1951050", "Nguyen Van Hao", 1999);
studentB = studentA;
studentB.print();
return 0;
}
That being said, you are using types that the compiler already knows how to copy, so you should let the compiler generate a suitable copy assignment operator for you, eg:
#include <iostream>
using namespace std;
class STUDENT {
public:
string ID;
string name;
unsigned int birthyear;
STUDENT(string x, string y, unsigned int z) {
ID = x;
name = y;
birthyear = z;
}
//STUDENT& operator=(STUDENT const &) = default;
void print() const {
cout << ID << " " << name << " " << birthyear;
}
};
int main() {
STUDENT studentA("1951049", "Nguyen Vinh Hao", 2001);
STUDENT studentB("1951050", "Nguyen Van Hao", 1999);
studentB = studentA; // <-- automatically does the "right thing" for you!
studentB.print();
return 0;
}
In your case, you do not need to implement your own copy assignment operator=, because both std::string and (unsigned) int types have their own built-in copy operator. In other words, they know how to copy safely their own resources.
As #Remy Lebeau already suggested the best option is to use the default:
class_name & class_name :: operator= ( const class_name & ) = default;
Even if you used Containers from the standard template library containers as your member variables,
class STUDENT {
public:
string ID;
string name;
unsigned int birthyear;
vector v; /*for example std::vector*/
};
again, you shouldn't need to worry about copying, moving, or managing the memory of your class. They handle their resources!
The container manages the storage space that is allocated for its
elements and provides member functions to access them, either directly
or through iterators (objects with properties similar to pointers).
You should start worrying about copy semantics when you introduce pointers in your classes, given that those pointers are responsible for managing the resources where they point to!
class STUDENT {
public:
string ID;
string name;
unsigned int birthyear;
float * p; /* this can introduce bug if not handled properly */
};
You can read more on previous questions:
here, and here
Here STUDENT *res; is currently not pointing anywhere and so you can't assign it values.
You don't need STUDENT *res; here
You can just return obj;
or if you want obj to be assigned to another pointer and then return it, you can do
STUDENT operator=(STUDENT const &obj)
{
const STUDENT *res;
res = &obj;
//here the pointer res points to the same address as the obj, thus they are pointing to same object.
return *res;
}
I am trying to make an object as a parameter for my add() function in this code:
class EnterInfo
{
protected:
string name;
int age;
string birthmonth;
public:
EnterInfo()
{
}
EnterInfo(string n, int a, string b)
{
name = n;
age = a;
birthmonth = b;
}
};
class CourseInfo
{
protected:
string title;
public:
CourseInfo()
{
}
CourseInfo(string t)
{
title = t;
}
void add()
{
}
};
int main()
{
EnterInfo s1;
CourseInfo c1;
s1 = EnterInfo("Sand", 20, "Jan");
c1 = CourseInfo(" x Records");
}
I want the add() function to gather all the data from the object "s1" and compact it into an array that I can access later. I could add, remove, or edit the data moving forward or even maybe make a new object "c2" which contains "y records" with the same s1 values ("sand", 20, "Jan"), however, I have no idea how to implement this in code.
c1.add(s1); // assume s1 (EnterInfo): Sand 20 Jan
c1.add(s2); // assume s2 (EnterInfo): Paul 23 Aug
this is the code I want to work with. I don't know how to make it work though. The end game would be this
c1.print();
output:
x records
Sand 20 Jan
Paul 23 Aug
create a vector of EnterInfo objects and put it in CourceInfo class. The code below does what you need:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class EnterInfo
{
public:
string name;
int age;
string birthmonth;
EnterInfo()
{
name = "";
age = 0;
birthmonth = "";
}
EnterInfo(string n, int a, string b)
{
name = n;
age = a;
birthmonth = b;
}
};
class CourseInfo
{
protected:
string title;
vector<EnterInfo> info_vec;
public:
CourseInfo()
{
title = "";
}
CourseInfo(string t)
{
title = t;
}
void add(const EnterInfo enterInfo)
{
this->info_vec.push_back(enterInfo);
}
void print() {
cout << this->title << endl;
for (const auto& it : this->info_vec) {
cout << it.name << " " << it.age << " " << it.birthmonth << endl;
}
}
};
int main()
{
EnterInfo s1("Sand", 20, "Jan");
EnterInfo s2("Arash", 21, "Feb");
CourseInfo c1(" x Records");
c1.add(s1);
c1.add(s2);
c1.print();
}
Side notes:
1- It's better to assign default values to the members of your class in the constructor.
2- I changed the access level of your EnterIndo members into public in order to use them in add function but the standard way is to set them to private and create getters and setters for them.
Research about std::vector and get/setters if you are not familiar with them.
I got some problem when run my coding. I got 2 separate file to create RetailItem class and create main. I create both in project.
Below are main.cpp
//main
#include "retailitem.h"
#include <iostream>
#include <iomanip>
using namespace std;
using std::cout;
void displayItem(RetailItem *, const int);
int main()
{
const int Item = 3;
RetailItem ritem[Item] ={ { "Jacket", 12, 59.95 },
{ "Designer Jeans", 40, 34.95 },
{ "Shirt", 20, 24.95 } };
//cout << fixed << setprecision(2);
void displayItem(RetailItem *ritem, const int Item){
cout <<" DESCRIPTION UNITS ON HAND PRICE";
cout<<"=================================================================\n";
for (int i = 0; i < Item; i++)
{
cout << setw(12) << ritem[i].getDesc();
cout << setw(12) << ritem[i].getUnits();
cout << setw(8) << ritem[i].getPrice();
}
cout << "===================================================================";
}
return 0;
}
and there one more file retailitem.h
//RetailItem class
#include <string>
using namespace std;
class RetailItem
{
private:
string description;
int unitsOnHand;
double price;
public:
RetailItem(string,int,double);
void setDesc(string d);
void setUnits(int u);
void setPrice(double p);
string getDesc();
int getUnits();
double getPrice();
};
RetailItem::RetailItem(string desc, int units, double cost)
{
description = desc;
unitsOnHand = units;
price = cost;
}
void RetailItem::setDesc(string d)
{
description = d;
}
void RetailItem::setUnits(int u)
{
unitsOnHand = u;
}
void RetailItem::setPrice(double p)
{
price = p;
}
string RetailItem::getDesc()
{
return description;
}
int RetailItem::getUnits()
{
return unitsOnHand;
}
double RetailItem::getPrice()
{
return price;
}
when compile and run main,
[Error] a function-definition is not allowed here before '{' token
[Error] expected '}' at end of input
I don't know what to fix, how can I solve it?
The error message undoubtedly contained a line number that told you where the problem was. That's an important part of describing the problem. But here it happens to be obvious: void displayItem(RetailItem *ritem, const int Item){ is the start of a function definition. You can't define a function inside another function. Move this outside of main.
I need to creat an object Pokemon in the main()
that assign it into the class PokemonWorld, and let the PokemonWolrd to decide which PokemonStation is this Pokemon need to go
I tired get the data separatly (get name and hp) and get together(get a Pokemon class)
but both fail
#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
class Pokemon {
public:
Pokemon() {};
Pokemon(char x[], int n) {
strncpy_s(name, x, 10);
hp = n;
};
private:
char name[10];
int hp;
};
class PokemonStation {
private:
Pokemon **list= new Pokemon*[1000];
public:
PokemonStation() {};
PokemonStation(int x) {
id = x;
};
int id;
void assigntoList(int i,Pokemon x)
{
if (i > 0)
i--;
list[i] = new Pokemon(x);
cout << "creat" << list[i];
};
};
class PokemonWorld {
private:
char name[10];
public:
PokemonStation s1;
PokemonStation s2;
PokemonWorld() {};
PokemonWorld(char x[], int y=1, int z=2) {
strncpy_s(name, x, 10);
PokemonStation s1(y);
PokemonStation s2(z);
};
const char* const getName() const{
return name;
};
void assigntoStation(int i,Pokemon x) {
if (i == 0 || i % 2 == 0)
s1.assigntoList(i, x);
else
s2.assigntoList(i, x);
};
};
void main() {
int number,hp,i;
char name[10];
cout << "What is the World Name ?" <<endl;
cin >> name;
PokemonWorld world(name);
cout << "Please input the number of Pokemon in the " << world.getName() <<" world:" << endl;
cin >> number;
Pokemon **mon = new Pokemon*[number];
cout << "Please input the characteristics of all Pokemon: Name HP" << endl;
for (i = 0;i < number;i++)
{
cin >> name >> hp;
mon[i] = new Pokemon(name, hp);
world.assigntoStation(i,*(mon[i]));
}
for (i = 0;i < number;i++)
cout << "world is " << world.getName() << endl;
system("pause");
};
In C++, you should use std::vectors for dynamic lists of things and std::strings for text. If you know Java, these are like ArrayList and String. (To use these, make sure you #include <vector> and <string>.)
For instance, your Pokemon class, rewritten with name as a string:
class Pokemon {
public:
Pokemon() {}
Pokemon(string name, int hp):name(name), hp(hp) { // construct the fields directly
}
private:
string name;
int hp;
};
And your PokemonStation class, rewritten using a vector for the list of Pokemon:
class PokemonStation {
private:
vector<Pokemon> list;
public:
PokemonStation() {}
PokemonStation(int x):id(x) {}
int id;
void assignToList(Pokemon x)
{
list.push_back(x); // add x to the list
}
};
If you want to print a Pokemon with cout <<, then you'll have to overload the << operator to define what gets printed. Add this into your class:
class Pokemon {
public:
...
friend ostream& operator<<(ostream& out, const Pokemon& p) {
out << p.name; // just print the name
return out;
}
...
};
Just make sure that you're couting a Pokemon, not a pointer-to-Pokemon (Pokemon*), and you won't get an address.
for example lets have a class or struct name Employee with two constructors, a default constructor and a constructor with parameters two strings and an int. why doesn't the following code work?
Employee *employees = (employee*) malloc(sizeof(Employee)*10);
let's say we have an array, size 10, of type string for first name, last name, and one of type int for salary. how to initialize the data members of each object class using the constructor with the parameters?
for (int i = 0; i < 10; i++)
{
employees[i] = employee(firstname[i], lastname[i], salary[i]);
}
I've been trying to do this for a few days now but wasn't successful. Also, can anyone tell how to do this using c++'s new and delete operator? and also is there a way this can be done using vectors?
Thank you
header file
class employee{
std::string firstname;
std::string lastname;
int salary;
public:
employee(std::string, std::string , int);
employee();
void setFirst(std::string);
void setLast(std::string);
void setSalary(int);
std::string getFirst();
std::string getLast();
int getSalary();
};
employee::employee(std::string x, std::string y, int z)
{
setFirst(x);
setLast(y);
setSalary(z);
}
void employee::setFirst(std::string x)
{
firstname = x;
}
void employee::setLast(std::string y)
{
lastname = y;
}
void employee::setSalary(int z)
{
salary = z > 0 ? z : 0;
}
std::string employee::getFirst()
{
return firstname;
}
std::string employee::getLast()
{
return lastname;
}
int employee::getSalary()
{
return salary;
}
.cpp file
#define MAX 20
using namespace std;
int main(int argc, char* argv[])
{
int n = 1;
cout << "number of employees: ";
cin >> n;
string firstname[MAX];
string lastname[MAX];
double salary[MAX];
float raise[MAX];
for (int i = 0; i < n; i++)
{
cout << "Employee " << i + 1 <<endl;
cout << "-----------\n";
cout << "First Name: ";
cin >> firstname[i];
cout << "Last Name: ";
cin >> lastname[i];
cout << "Monthly Salary: ";
cin >> salary[i];
salary[i] *= 12;
cout <<"Yearly percentage raise (e.g 10% or 0%): ";
scanf("%f%%", &raise[i]);
salary[i] *= (((raise[i])/100.00) + 1);
puts("\n");
}
employee *employees = (employee*) malloc(sizeof(employee)*10);
for (int i = 0; i < n; i++)
{
employees[i] = employee(firstname[i], lastname[i], salary[i]);
}
cout << "TESING USING GET FUNCTIONS" << endl;
cout << "---------------------------\n\n";
for (int i = 0; i < n; i++)
{
cout << "Employee " <<i +1<< endl;
cout <<"-----------\n";
printf("First Name: %s", employees[i].getFirst().c_str());
printf("\nLast Name: %s",employees[i].getLast().c_str());
printf("\nYearly Salary: %d\n\n", employees[i].getSalary());
}
}
If you have an array of Employee instances and Employee is not POD (http://en.wikipedia.org/wiki/POD) you need to allocate memory from the stack using the operator new:
Employee* employees = new Employee[10];
And for having this working:
for (int i = 0; i < 10; i++)
{
employees[i] = Employee(firstname[i], lastname[i], age[i]);
}
you need to implement the operator= in your Employee class:
Employee& operator=(const Employee& src)
{
_firstname = src._firstname;
_lastname = src._lastname;
_age = src._age;
return *this;
}
If this looks like your Employee class:
class Employee
{
std::string first_name;
std::string last_name;
// other members and functions ...
};
Then using malloc() to create 10 of these is a complete and utter failure. The reason why is that yes, you allocated memory using malloc(), but that's all you did. You didn't construct 10 Employee objects. Those std::string members need to be constructed, not merely have memory allocated. So with that call to malloc() you have 10 fake Employees that were "created", and as soon as you attempt to do anything with one of them, then boom goes your program.
Do research on POD and non-POD types. You cannot treat non-POD types (as the class above is non-POD) as you would a POD type. For a non-POD type, the instance must be "officially" constructed, (the constructor must be invoked).
On the other hand, malloc() knows nothing concerning C++ and what is required to create an object correctly via construction. All malloc (and calloc, and realloc) knows is to allocate bytes and return a pointer to the allocated space.
Use a vector instead, it's resizable, it's easier to manage, and as Grady stated in his comment, it's also generally not good practice to use malloc in C++ code (although it's possible). Maybe do something that looks like this:
#include <vector>
...
int size = 10;
std::vector<Employee *> employees;
for(int i = 0; i < size; i++)
{
//as far as pulling in your data, that depends on where it's coming from
Employee *temp = new Employee(...);
employees.push_back(temp);
}
I'm rusty on my C++ but this should work.
Try this way:
#include <iostream>
class Employee
{
std::string m_firstname;
std::string m_lastname;
int m_age;
public:
Employee()
{
m_firstname=m_lastname="";
m_age=0;
}
void setFirstName(std::string firstname)
{
m_firstname=firstname;
}
void setLastName(std::string lastname)
{
m_lastname=lastname;
}
void setAge(int age)
{
m_age=age;
}
void displayEmp()
{
std::cout<<m_firstname;
std::cout<<m_lastname;
std::cout<<m_age;
}
};
int main()
{
std::string fname;
std::string lname;
int age;
Employee *employee = new Employee[10];
Employee *employeeptr=employee;
for(int i=0;i<10;i++)
{
std::cin>>fname;
std::cin>>lname;
std::cin>>age;
employeeptr->setFirstName(fname);
employeeptr->setLastName(lname);
employeeptr->setAge(age);
employeeptr++;
}
employeeptr=employee;
for(int i=0;i<10;i++)
{
employeeptr->displayEmp();
employeeptr++;
}
delete []employee;
return 0;
}