Dealing with errors due to different constructors in the code while allocating new memory in object oriented programming

Viewed 112

I want to allocate new memory for my class which has some derived classes as well. as I have defined a constructor of type Professor(string name,int age,int publications,int cur_id) memory allocation per[i] = new Professor; in the main throws error:no matching function for call to 'Professor::Professor(). another error I am getting is candidate: 'Professor::Professor(std::string, int, int, int) expects 4 arguments, 0 provided. please help me how to define a constructor which allocates memory without giving any error, thanks.

ps: I am trying to solve this question

part of my class looks like;

class Person{
    protected:
        string name;
        int age;
    public:
    Person(string name,int age){
        name=name;
        age=age;
    }
    int z=0;
        void getdata(){
            string m;int n;
            cin>>m>>n;
            z++;
            Person(m,n);
        }
        void putdata(){
            cout<<name<<" "<<age<<endl;
        }
};
class Professor: public Person{
    public:
        int publications;
        int cur_id;
        Professor(string name,int age,int publications,int cur_id)
            :Person(name,age)
        {
            publications=publications;
            cur_id=cur_id;       
        }
        int b=0;
        void getdata(){
            string a;int b,c;
            cin>>a>>b>>c;
            b++;
            Professor(a,b,c,b);
        }
        void putdata(){
            cout<<name<<" "<<age<<" "<<publications<<" "<<cur_id<<endl;
        }
};
class Student:public Person{
public:
    int marks[6];
    int cur_id;
    Student(string name,int age,int arr[6],int cur_id)
        :Person(name,age)
    {
        marks[6]=arr[6];
        cur_id=cur_id;
    }
    int s=0;
    void getdata(){
        string p;int q;int r[6];
        cin>>p>>q;
        for(int i=0;i<6;i++){
            cin>>r[i];
        }
        s++;
        Student(p,q,r,s);
    }
    void putdata(){
        cout<<name<<" "<<age<<" "<<marks[0]<<" "<<marks[1]<<" "<<marks[2]<<" "<<marks[3]<<" "<<marks[4]<<" "<<marks[5]<<" "<<cur_id<<endl;
    }

};

My main function looks like

int main(){

    int n, val;
    cin>>n; //The number of objects that is going to be created.
    Person *per[n];

    for(int i = 0;i < n;i++){

        cin>>val;
        if(val == 1){
            // If val is 1 current object is of type Professor
            per[i] = new Professor;

        }
        else per[i] = new Student; // Else the current object is of type Student

        per[i]->getdata(); // Get the data from the user.
    }

    for(int i=0;i<n;i++)
        per[i]->putdata(); // Print the required output for each object.

    return 0;
}
3 Answers

Your problem has nothing to do with dynamic allocations. You are trying to construct Professors and Students by calling their default constuctor (new Professor / new Student), but they don not have a default constructor.

A default constructor is a constructor that can be called without parameters. You can change existing constructors:

 Person(string name = "",int age = 42) : name(name), age(age) {}

And similar for Student. Note that your constructor implementation was wrong. You assigned the parameters to themself but did not initialize the members. The member initialization list is a special place where you can use the same name for member and argument without shadowing.

Alternatively call the constructor with parameters.

Glad to see you are trying to improve your C++ skills. However, there are few things you can do to improve the code quality and style:

  1. per[i]->getdata(); // Get the data from the user. will not work.
    1. You have not defined getdata() with a virtual prefix.
    2. Mark the overloaded methods in your child classes with an override suffix.
  2. The same problem exists for putdata()
  3. Virtual destructor is missing.
  4. Is it valid to create a Person object? I think not. Therefore:
    1. Constructor can be protected.
    2. Person::getdata() can be a pure virtual function.
  5. Person::z is a public member variable.
  6. Member variables in child classes (Student and Professor) are also public.
  7. Mentioned already by @463035818_is_not_a_number that Person *per[n]; is not portable C++.
  8. As suggested by @JulienLopez, generally avoid raw pointers in C++11 and above. Use std::shared_ptr or std::unique_ptr.

I think you're missing the point of a constructor a bit here.

The idea is to have all the data ready to create your instance before hand, and then instanciate your class (either Professor or Student).

So your constructors are good, but you getdata member functions are not.

The easiest way would be for your getdata functions to become free functions (or static member functions, in our case, it's pretty much the same), and they gather the datas needed for construction and instanciate your class. (and a clearer name wouldn't hurt while we're at it)

Professor* createProfessorFromCin()
{
        string a;int b,c;
        cin>>a>>b>>c;
        return new Professor(a,b,c,b+1);
}

and your calling code would just end up as

per[i] = createProfessorFromCin();

for example.

Also, few tips if you plan on improving this piece of code:

  • use smart pointers, it's not the 90's anymore, your code well be a lot more memory safe (on the same vein, std::vector or std::array would be nice for the grades too)
  • If you plan on adding more subclasses of the sort, you should look into the Factory pattern for more OCP-friendly code.
  • Your Person class needs a virtual destructor (once you will fix your memory issues), otherwise your instances won't get destroyed properly.
Related