3

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;
}
def __init__
  • 1,092
  • 6
  • 17
  • 2
    `per[n]` is not standard C++. Use a `std::vector` for dynamically sized arrays. [Why aren't variable-length arrays part of the C++ standard?](https://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard) – 463035818_is_not_an_ai Jun 17 '21 at 12:23
  • i think per[n] just deals with variable name, main problem is due to my defined constructor which differs from the type memory is allocated i think – def __init__ Jun 17 '21 at 12:25
  • I didnt say that this solves your errors. But currently your code is not portable C++, because it is using a compiler extension. Compiler extensions should be used with care, while `std::vector` is pretty standard – 463035818_is_not_an_ai Jun 17 '21 at 12:28
  • @Rajakr Your `Person` class lacks a virtual destructor. Thus issuing a `delete` call on any of those `per` entries that are not actual pointers to `Person` will invoke undefined behavior. – PaulMcKenzie Jun 17 '21 at 12:42

3 Answers3

2

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.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • thank you sir,i have added my student class as well in the code, yeah the problem is due to the calling of the default constructor which I am unable to deal with the existing constructor for professor and students. if you may add the way i should initialize constructor for student class so that it don't collide when i call default constructor new professor will be of huge help. – def __init__ Jun 17 '21 at 12:38
  • @Rajakr sorry, not sure if I understand your comment. What I posted in the question is a default constructor. To call the constructor with parameters, you just need to call it with parameters. `Student st{"name",age};` or if you insist on `new` then `new Student("name",age);` – 463035818_is_not_an_ai Jun 17 '21 at 13:56
  • @ 463035818_is_not_a_number,Thank you, sir, I got your point. – def __init__ Jun 17 '21 at 14:16
2

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.
Daniel Dearlove
  • 565
  • 2
  • 12
  • Thank you so much brother, it helped me to understand a lot what I need to work on for improvement. – def __init__ Jun 17 '21 at 13:30
  • brother you perfectly pointed out per[i]->getdata(); // Get the data from the user. will not work, may you help how to modify my existing member function getdata to make it work. – def __init__ Jun 17 '21 at 14:20
  • You need polymorphic behaviour in each of your subclasses. Each subclass does something different when `ptr->getdata()` and `ptr->putdata()` is called. You tell the C++ compiler to enable polymorphic behaviour by prefixing [`virtual`](https://en.cppreference.com/w/cpp/language/virtual) to the appropriate member functions. Other languages do this automatically but C++ does not. It is good modern C++ style to mark the overloaded methods in you child classes with an `override` suffix. – Daniel Dearlove Jun 17 '21 at 14:29
1

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.
Dharman
  • 30,962
  • 25
  • 85
  • 135
Julien Lopez
  • 1,021
  • 6
  • 14