Reputation:
I've got a class person that include name, ID and static constructor. I defined a copy constructor that copy only name to defining person. Does anyone know why ID and counter aren't shown correctly after defining per_2? Do I have to define ID somehow that it's an exception and can't be copied?
#include<iostream>
#include<string>
using namespace std;
class person {
public:
string name;
int ID;
static int counter;
person();
~person();
person(const person & );
};
int person::counter = 0;
person::person() {
counter++;
ID = counter;
}
person::~person() {
}
person::person(const person & obj) {
this - > name = obj.name; //Here I define that only name is supposed to be copied
}
int main() {
person per_1;
per_1.name = "John";
cout << per_1.ID << endl; // It gives 1 and it's fine.
cout << person::counter << endl; // So does it.
person per_2 = per_1; // Here I copy class and give per_1's variables to per_2.
cout << per_2.ID << endl; // Here I expect 2, because constructor incremented counter and assigned it to per_2.ID while it gives -84534283.
cout << person::counter << endl; // There is still 1, despite incrementing counter in constructor.
system("Pause");
return 0;
}
Upvotes: 1
Views: 211
Reputation: 117298
The default constructor is not called when you use the copy constuctor, but you can add a converting constructor that creates a person
from a name
and delegate to that constructor in other constructors. I suggest delete
ing the copy constructor and replacing it with a default
move constructor though. You probably don't want two person
s with the same ID.
Example:
#include <iostream>
class person {
public:
int ID;
std::string name;
static int counter;
person(); // default ctor
explicit person(const std::string&); // converting ctor
person(const person &) = delete; // copy ctor deleted to not get two persons
// with the same ID
person(person&&) = default; // move ctor
};
int person::counter = 0;
person::person() :
person("") // delegate
{}
person::person(const std::string& Name) : // colon starts the member initializer list
ID(++counter),
name(Name)
{}
You can replace the separate default constructor and the converting constructor with one constructor by using a default value for name:
person(const std::string& Name = {}) :
ID(++counter),
name(Name)
{}
Upvotes: 2
Reputation: 137
When you invoke the copy constructor, the default constructor is ignored. Both an individual person's ID as well as person::counter
are only altered by the default constructor, so this means that they will be ignored when the copy constructor is called. Your program is allocating memory for per_2's name and ID, which have dummy values to begin with, then the name is overwritten to be a copy of per_1's name and it's done. In your copy constructor, you also need to specify what the ID should be as well as person::counter
or no changes will be made. You could add these two functionalities into a helper method that is called by both the default constructor and the copy constructor for cleaner code, if you wish.
Upvotes: 0
Reputation: 32732
The default constructor is not executed when the copy constructor is called. As a result, ID
is not initialized in per_2
.
You'll need to duplicate the code from the default constructor to assign the next available ID (or add a private member function to do that, and have both constructors call it).
Upvotes: 1