user13229658
user13229658

Reputation:

Copying class by constructor in C++

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

Answers (3)

Ted Lyngmo
Ted Lyngmo

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 deleteing the copy constructor and replacing it with a default move constructor though. You probably don't want two persons 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

Shaavin
Shaavin

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

1201ProgramAlarm
1201ProgramAlarm

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

Related Questions