Reputation: 800
I have a class "Employee" I want to create a array of pointers for that.
Will this work out?
Employee *employeeArr[size];
In my "for loop" something like this
employeeArr[i] = new Employee(surname , firstname , gender); // constructor implemented Employee( para1, para2, para3)
OR should I write
Employee *employeeArr = new Employee[size];
And fill everything with "dots" like
employeeArr[i].setSurname(surname);
Can you explain the reason as well, I'm really new to pointers. The second one was told to me by someone else but I couldn't get an answer as to why I can't use the first one. Also if possible, do not mention std::array or std::vector, I'm still too new
Upvotes: 5
Views: 368
Reputation:
Sorry to surprise you:
None of the examples you give should be considered as as the "correct way" to handle collections of classes in c++.
Also if possible, do not mention std::array or std::vector, I'm still too new
No, that's the wrong path hauling up the mare. The proper usage of raw pointers and raw arrays is certainly beyond your capabilities, if you can't grasp how to deal with std::array
or std::vector
primarily.
Supposed your Employee
class looks like
struct Employee {
std::string surname_;
std::string firstname_;
enum Gender {
Female = 'F' ,
Male = 'M' ,
Unxpecified = 'X'
} gender_;
};
and you have an overload for the std::operator>>()
std::istream& operator>>(std::istream& is, Employee& employee) {
char genderSymbol;
is >> employee.surname_ >> employee.firstname_ >> genderSymbol;
switch(genderSymbol) {
case 'F':
case 'M':
case 'X':
employee.gender_ = (Employee::Gender)genderSymbol;
break;
default:
is.setstate(std::ios_base::failbit);
break;
}
}
One good and idiomatic way to represent that Employee
array would be to use a
std::vector<Employee> employeeArr;
and fill it in a loop:
Employee employee;
while(std::cin >> employee) {
employeeArr.emplace_back(employee);
}
If you really need pointers (references) you may consider to use smart pointers as provided with the Dynamic Memory Management utility classes.
For instance you may decide to have a
std::vector<std::unique_ptr<Employee>> employeeArr;
and initialize it like
while(std::cin >> surname >> firstname >> gender) {
employeeArr.emplace_back(std::make_unique<Employee>(surname , firstname , gender));
}
This comes into consideration if you want to manage pools of hierarchically organized class instances like:
struct Employee {
virtual ~Employee() {}
std::string surname_;
std::string firstname_;
enum Gender {
Female = 'F' ,
Male = 'M' ,
Unxpecified = 'X'
} gender_;
};
struct IForeman : Employee {
virtual std::vector<const Employee const*> TeamMembers() const = 0;
virtual void AddTeamMember(const Employee const* member) = 0;
};
class Foreman : public IForeman {
str::vector<const Employee const*> teamMembers_;
public:
std::vector<const Employee const*> TeamMembers() const {
return teamMembers_;
}
void AddTeamMember(const Employee const* member) {
teamMembers_.push_back(member);
}
};
Consider to hand out owned or shared pointers to related connections using plain const
pointers.
Upvotes: 4
Reputation: 51890
Also if possible, do not mention std::array or std::vector, I'm still too new
You got it backwards. If you are too new, then you should be using std::array
and std::vector
. Do not use built-in arrays and do not do manual memory management if you're new.
What you should be using, is:
#include <array>
// ...
std::array<Employee, size> employeeArr;
if size
is known at compile-time and will never change. If it's not known at compile-time, or if the array needs to grow dynamically, then use vector
:
#include <vector>
// ...
std::vector<Employee> employeeArr;
and then add Employee
objects to it using push_back()
:
employeeArr.push_back(Employee(/* ... */));
And there's no pointers involved here either. Just values.
Once you get more familiar with containers, then you can delve deeper into C++ and learn about pointers and memory management.
Upvotes: 2
Reputation: 3911
Employee *employeeArr[size];
is an array of Employee pointers so the size is static which is known at compile-time. Whereas Employee *employeeArr = new Employee[size];
is a pointer to a dynamic array of Employee objects; not pointers.
Make difference and use each cautiously.
You can use class vector
where you don't matter of allocatio-de-allocation of dynamic memory.
Here is an example showing the 3 possible usages:
#include <iostream>
#include <vector>
#include <string>
class Employee{
public:
Employee(){} // Imporatant for a dynamic array of objects
Employee(const std::string, const std::string, const bool);
void set(const std::string, const std::string, const bool);
// some other methods here
void print()const;
private:
std::string surName, firstName;
bool gender;
};
Employee::Employee(const std::string sur, const std::string first, const bool gend) :
surName(sur),
firstName(first),
gender(gend){
}
void Employee::set(const std::string sur, const std::string first, const bool gend){
surName = sur;
firstName = first;
gender = gend;
}
void Employee::print()const{
std::cout << "surName: " << surName << std::endl;
std::cout << "firsName: " << firstName << std::endl;
gender ? std::cout << "Male" : std::cout << "Female" ;
std::cout << std::endl;
}
int main(){
// 1: An array of pointers:
Employee* empl[3];
std::string surName, firstName;
bool gender;
for(auto i(0); i != 3; ++i){
std::cout << "surName: ";
std::cin >> surName;
std::cout << "firstName: ";
std::cin >> firstName;
std::cout << "gender: ";
std::cin >> gender;
empl[i] = new Employee(surName, firstName, gender);
}
for(auto i(0); i != 3; ++i)
empl[i]->print();
std::cout << "_________________________" << std::endl;
// 2: A pointer to a dynamic array:
Employee* empl2 = new Employee[3]; // default constructor is imortant here
for(auto i(0); i != 3; i++){
std::cout << "surName: ";
std::cin >> surName;
std::cout << "firstName: ";
std::cin >> firstName;
std::cout << "gender: ";
std::cin >> gender;
empl2[i].set(surName, firstName, gender);
}
for(auto i(0); i != 3; ++i)
empl2[i].print();
delete[] empl2;
std::cout << "_________________________" << std::endl;
// 3: with vectors:
std::vector<Employee> vecEmpl; // default ctor is not important here
for(auto i(0); i != 3; ++i){
std::cout << "surName: ";
std::cin >> surName;
std::cout << "firstName: ";
std::cin >> firstName;
std::cout << "gender: ";
std::cin >> gender;
Employee emp(surName, firstName, gender);
vecEmpl.push_back(emp);
}
for(auto i(0); i != 3; ++i)
vecEmpl[i].print();
std::cout << std::endl << std::endl;
return 0;
}
Upvotes: 0
Reputation: 4654
The first example creates an array of pointers to Employee
objects, while the second one creates a dynamically allocated array of Employee
s. These are completely different things.
If you don't understand vectors, you should not be messing with pointers because they are easy to misuse. I would recommend learning C++ step by step with a good book if you don't already have one.
As far as I know, in most situations, the size of a static array must be a constant expression (able to be computed at compile time). That's why your first example does not work. If you want arrays with an unknown size then you should use vectors or dynamic arrays.
Once you understand vectors you will realize that they are much more convenient than dynamic arrays since they handle things like freeing memory automatically for you. Another nice thing about vectors is that you can resize them after they are created.
Upvotes: 1
Reputation: 1799
C++ is a very flexible language, and the decision is completely yours.
For example:
vector<shared_ptr<Employee> > employees;
employees.push_back(make_shared<Employee>(surname, firstname, gender));
make_shared
makes a (shared pointer) of the newly created employee.
Shared pointer is an automatically reference-counted pointer, which is great in threading and in sharing object (pointer to object) between different objects.
You can see this question for an example of using unique_ptr
Upvotes: 0