Polymorphism using pointer to array

  • Thread starter yungman
  • Start date
  • Tags
    Array
In summary, the main() is trying to create an array of GradedActivity pointers and initialize each pointer with a dynamically allocated object.
  • #1
yungman
5,718
241
I am looking at the program 15.13 in the Gaddis book. My question is only regarding of int main(){} that using pointer tests of GradedActivity to point to an array. I am trying to understand how it works. I reviewed on pointer to dynamic allocation of memory for array and try to change the code, it obviously doesn't work.

This is the whole program:
C++:
#include <iostream>
#include <iomanip>
using namespace std;
class GradedActivity
{protected:  double score;   // To hold the numeric score
public:
    GradedActivity()     { score = 0.0; }
    GradedActivity(double s) { score = s; }
    void setScore(double s)  { score = s; }
    double getScore() const  { return score; }
    virtual char getLetterGrade() const
    {  char letterGrade; // To hold the letter grade
       if (score > 89)letterGrade = 'A';
       else if (score > 79)letterGrade = 'B';
       else if (score > 69)letterGrade = 'C';
       else if (score > 59)letterGrade = 'D';
       else  letterGrade = 'F';
       return letterGrade;
    }
};
class PassFailActivity : public GradedActivity
{protected:   double minPassingScore;    // Minimum passing score.
public:
    PassFailActivity() : GradedActivity()
    {
        minPassingScore = 0.0;
    }
    PassFailActivity(double mps) : GradedActivity()
    {
        minPassingScore = mps;
    }
    void setMinPassingScore(double mps)
    {
        minPassingScore = mps;
    }
    double getMinPassingScore() const
    {
        return minPassingScore;
    }
    virtual char getLetterGrade() const
     {  char letterGrade;
        if (score >= minPassingScore)  letterGrade = 'P';
        else letterGrade = 'F';
        return letterGrade;
     }
};
class PassFailExam : public PassFailActivity
{private: int numQuestions; double pointsEach; int numMissed;
public:
    PassFailExam() : PassFailActivity() {
        numQuestions = 0;
        pointsEach = 0.0;
        numMissed = 0;
    }
    PassFailExam(int questions, int missed, double mps) : PassFailActivity(mps)
    {
        set(questions, missed);
    }
    void set(int questions, int missed)
    {   double numericScore;
        numQuestions = questions;
        numMissed = missed;
        pointsEach = 100.0 / numQuestions;
        numericScore = 100.0 - (missed * pointsEach);
        setScore(numericScore);
    }
    double getNumQuestions() const { return numQuestions; }
    double getPointsEach() const { return pointsEach; }
    int getNumMissed() const  {   return numMissed; }
};

void displayGrade(const GradedActivity* activity)
{    cout << setprecision(1) << fixed<<" The activity's numeric score is "<<
        activity->getScore()<< "\n The activity's letter grade is " <<
        activity->getLetterGrade() << "\n\n";
}
int main()
{   const int NUM_TESTS = 4;
    GradedActivity* tests[NUM_TESTS] =// tests is array of GradedActivity pointers.
    { new GradedActivity(88.0),       // Each element of tests is initialized with the
      new PassFailExam(100, 25, 70.0),// address of a dynamically allocated object.
      new GradedActivity(67.0),
      new PassFailExam(50, 12, 60.0)
    };
    for (int count = 0; count < NUM_TESTS; count++)
    { cout << "Test #" << (count + 1) << ":\n";
        displayGrade(tests[count]);
        cout << endl;
    }
    return 0;
}

The main() I am trying to use is:
C++:
int main()
{    const int NUM_TESTS = 4;
    GradedActivity* tests;
    tests = new GradedActivity[NUM_TESTS];
    tests[0] = GradedActivity(88.0);
    tests[1] = PassFailExam(100, 25, 70.0);
    tests[2] = GradedActivity(67.0);
    tests[3] = PassFailExam(50, 12, 60.0);
    for (int count = 0; count < NUM_TESTS; count++)
    {
        cout << "Test #" << (count + 1) << ":\n";
        displayGrade(tests[count]);
        cout << endl;
    }
    return 0;
}

This is the error message:
Array error.jpg

This is more the way I learn, I think there is a problem because the size of GradedActivity and PassFailExam must be different. Just want to verify this cannot be done or I just have some problem with the codes and can be fixed.

Thanks
 
Last edited:
Technology news on Phys.org
  • #2
The *tests array holds pointers to GradedActivity objects. It doesn't matter how memory is allocated to a GradedActivity object vs a PassFailActivity object since both are GradedActivity objects.

Basically *tests is an array of pointers! The pointers must be of type GradedActivity which means they can be either a GradedActivity object or a PassFailActivity object.

From the example, you can begin to see the power of the OO paradigm of polymorphism. You can also see why @Mark44 and I felt that using GradedActivity as the parent was a poor choice.

Most experienced programmers would define a more neutral parent like CourseActivity for both GradedActivity and PassFailActivity. CourseActivity would be defined as an abstract class so it could only be used as a template for other classes. GradedActivity and PassFailActivity both could inherit the score attribute from CourseActivity and then override some CourseActivity methods by providing different method implementations for methods like displayGrade().
 
Last edited:
  • Like
Likes yungman
  • #3
jedishrfu said:
The *tests array holds pointers to GradedActivity objects. It doesn't matter how memory is allocated to a GradedActivity object vs a PassFailActivity object since both are GradedActivity objects.

Basically *tests is an array of pointers! The pointers must be of type GradedActivity which means they can be either a GradedActivity object or a PassFailActivity object.
So The way I wrote the main() is not wrong then? Must be some stupid things I I don't see. Don't tell me is one of those "const" problem again. I did try blindly with no luck before I posted.

There are so many different ways to write things, I just want to make sure I understand them. It should be a standard declaration of array of objects.

Thanks
 
  • #5
jedishrfu said:
Try this instead:
Code:
GradedActivity tests[NUM_TESTS];
Still no luck:
Array error 1.jpg

I think what you suggested is just another way of the same as mine, I allocate new memory, you just create an array. You see the wiggle red line under tests in line105? The error message talked about the "const" stuff...AGAIN! I am starting to dislike the word const!

Thanks
 
  • #9
jedishrfu said:
It worked?
No!
 
  • Sad
Likes jedishrfu
  • #11
jedishrfu said:
I've been out of C++ world for over 20 years doing mostly Java now.

I found this Stack article:

https://stackoverflow.com/questions/38919859/initializing-array-of-pointers-in-c

Maybe try

C++:
GradedActivity *tests[NUM_TESTS];
Yes, I reviewed the notes on array of class objects already and pointer to create dynamic memory like test = new GradedActivity[num].
jedishrfu said:
Sorry, no luck again:
Array error 2.jpg


I follow exactly what you are doing, I have suspicion the problem is not in this area.

Thanks
 
  • #12
I eliminated the for loop as shown, it compiled for both my version and yours:

This is mine:
C++:
int main()
{
    const int NUM_TESTS = 4;
    GradedActivity* tests;
    tests = new GradedActivity[NUM_TESTS];
    tests[0] = GradedActivity(88.0);
    tests[1] = PassFailExam(100, 25, 70.0);
    tests[2] = GradedActivity(67.0);
    tests[3] = PassFailExam(50, 12, 60.0);
    /*    for (int count = 0; count < NUM_TESTS; count++)
        {
            cout << "Test #" << (count + 1) << ":\n";
            displayGrade(tests[count]);
            cout << endl;
        }*/
    return 0;
}

This is yours:
C++:
int main()
{    const int NUM_TESTS = 4;
    GradedActivity tests[NUM_TESTS];
    //tests = new GradedActivity[NUM_TESTS];
    tests[0] =  GradedActivity(88.0);
    tests[1] =  PassFailExam(100, 25, 70.0);
    tests[2] =  GradedActivity(67.0);
    tests[3] =  PassFailExam(50, 12, 60.0);
/*    for (int count = 0; count < NUM_TESTS; count++)
    {
        cout << "Test #" << (count + 1) << ":\n";
        displayGrade(tests[count]);
        cout << endl;
    }*/
    return 0;
}

They both compile, so the problem is not in the array declaration. It's looked to be the stupid "const"!

thanks
 
  • #13
Line 3 should be *tests not tests and you should use "new" for the actual objects added.

That was a correction I made earlier.

The last link had a similar example using a Reader array

Code:
GradedActivity *tests[NUM_TESTS];  // notice the *tests

tests[0] = new GradedActivity(88.0);  // notice the use of new to create an instance of the class
tests[1] = new PassFailActivity(100,25,70.0);
tests[2] = new GradedActivity(90.0);
...
 
  • Like
Likes yungman
  • #14
jedishrfu said:
Line 3 should be *tests not tests and you should use "new" for the actual objects added.

That was a correction I made earlier.

The last link had a similar example using a Reader array

C++:
GradedActivity *tests[NUM_TESTS];  // notice the *tests

tests[0] = new GradedActivity(88.0);  // notice the use of new to create an instance of the class
tests[1] = new PassFailActivity(100,25,70.0);
tests[2] = new GradedActivity(90.0);
...
Yes, this works I got the right answer. It's funny I had it exactly like that and gave me error before.

Question is what is the difference between yours and mine? This is mine:
C++:
int main()
{    const int NUM_TESTS = 4;
    GradedActivity *tests;
    tests = new GradedActivity[NUM_TESTS];
    tests[0] =  GradedActivity(88.0);
    tests[1] =  PassFailExam(100, 25, 70.0);
    tests[2] =  GradedActivity(67.0);
    tests[3] =  PassFailExam(50, 12, 60.0);
    for (int count = 0; count < NUM_TESTS; count++)
    {
        cout << "Test #" << (count + 1) << ":\n";
        displayGrade(tests[count]);
        cout << endl;
    }
    return 0;
}
I use GradedActivity pointer tests to allocate 4 elements of memory, then I assign each element. What is the difference? Better yet, what did I do wrong?

Thanks
 
  • #16
jedishrfu said:
Try yours but make *tests as **tests
No, doesn't work.

BUT, I was playing around I put & in front of test in line 12, I got it to compile and produce result, BUT the two that point to PassFailExam only got the correct score but getting grade from GradedActivity instead of P or F from PassFailExam. This means the array works, but Polymorphism doesn't work to skip down from the base to the derived class.

C++:
int main()
{    const int NUM_TESTS = 4;
    GradedActivity *tests;
    tests = new GradedActivity[NUM_TESTS];
    tests[0] =  GradedActivity(88.0);
    tests[1] =  PassFailExam(100, 25, 70.0);
    tests[2] =  GradedActivity(67.0);
    tests[3] =  PassFailExam(50, 12, 60.0);
    for (int count = 0; count < NUM_TESTS; count++)
    {
        cout << "Test #" << (count + 1) << ":\n";
        displayGrade(&tests[count]);
        cout << endl;
    }
    return 0;
}

I am still thinking about what can I do to fix it. I really want to understand this array of objects in Polymorphism, not just blindly remember how to write to make it work. Time to review the pointers again!

Thanks for your help, how do you come up with your idea?
 
  • #17
jedishrfu said:
Line 3 should be *tests not tests and you should use "new" for the actual objects added.

That was a correction I made earlier.

The last link had a similar example using a Reader array

Code:
GradedActivity *tests[NUM_TESTS];  // notice the *tests

tests[0] = new GradedActivity(88.0);  // notice the use of new to create an instance of the class
tests[1] = new PassFailActivity(100,25,70.0);
tests[2] = new GradedActivity(90.0);
...
What is the meaning of line 1? Is tests[0..3] just an array of addresses only? This is each element contains just the 64bit address, nothing more. Then you use each of the element to create dynamic memory for the class object.

In another word, tests[0..3] is NOT an array of class objects.

Am I right?

thanks
 
  • #18
I haven't read the whole thread in detail so maybe you found out already, but the error you get in first post is because the displayGrade function takes a pointer to a GradedActivity, but in main you give it a
GradedActivity. So either change the displayGrade function to work with a const GradedActivity & instead (which is the idiomatic way of passing arguments in C++ without copying it and without having sensible meaning for the null value, which your case doesn't) or, for a smaller fix, change your call to displayGrade(&tests[count]);

By the way, the error message actually says this more or less directly, but I guess you got hung up on the const part of the types in that message and never noticed the pointer part which is the actual "missing part" in this case :wink:
 
  • #19
Filip Larsen said:
I haven't read the whole thread in detail so maybe you found out already, but the error you get in first post is because the displayGrade function takes a pointer to a GradedActivity, but in main you give it a
GradedActivity. So either change the displayGrade function to work with a const GradedActivity & instead (which is the idiomatic way of passing arguments in C++ without copying it and without having sensible meaning for the null value, which your case doesn't) or, for a smaller fix, change your call to displayGrade(&tests[count]);

By the way, the error message actually says this more or less directly, but I guess you got hung up on the const part of the types in that message and never noticed the pointer part which is the actual "missing part" in this case :wink:
Thanks,

I tried displayGrade(&tests[count]); in post 16, it ran, BUT Polymorphism did not work as described in post 16.

I am reviewing my pointers.

Thanks
 
  • #20
yungman said:
What is the meaning of line 1? Is tests[0..3] just an array of addresses only? This is each element contains just the 64bit address, nothing more. Then you use each of the element to create dynamic memory for the class object.

In another word, tests[0..3] is NOT an array of class objects.

Am I right?

thanks

Yes, you’re right. Pretty cool and usually the way programmers do it. We are basically memory jugglers. Every once in a while we fumble the juggle and the program crashes.
 
  • Like
Likes yungman
  • #21
jedishrfu said:
Yes, you’re right. Pretty cool and usually the way programmers do it. We are basically memory jugglers. Every once in a while we fumble the juggle and the program crashes.
Thanks for being with me all the way. I read on in the book, AFTER the program, it did say it is an array of pointers. Thanks a lot!

This morning, I put verified sizeof(tests)=16bytes, and sizeof(tests[0]) = 4bytes. That confirms it is an array of POINTERS, nothing more, so the whole thing is just allocating memory the size of the object using a pointer! Simple...after a night of digging!

Thanks for your help.
 
Last edited:
  • #22
yungman said:
This is each element contains just the 64bit address, nothing more.
yungman said:
This morning, I put verified sizeof(tests)=16bytes, and sizeof(tests[0]) = 4bytes.
Four bytes is 32 bits, not 64 bits. If you compile in x86 mode, or 32-bit mode (which you probably are doing) rather than x64 mode, pointers are 32 bits.
 
  • Like
Likes yungman
  • #23
Mark44 said:
Four bytes is 32 bits, not 64 bits. If you compile in x86 mode, or 32-bit mode (which you probably are doing) rather than x64 mode, pointers are 32 bits.
Yes sir, I was too happy, didn't even stop and think! My bad.
 
  • #24
@yungman ,
You may want to consider a classic problem as an exercise.

When Dan Bricklin made the first Visicalc spreadsheet program, the memory resources of personal computers were very small.

A spreadsheet has cells arranged in rows and columns. Today's Excel allows 64K rows and 64K columns, or more than 4 billion cells. (I don't remember the row/col limit of the original Visicalc. 256?) A cell is an object that can hold a formula, or a text string (of unspecified max length), or a numerical value, maybe even an image, or a BASIC program. So a cell can potentially take a lot of memory.

But 99.999% of the possible cells are empty. They should take no memory at all. Of the 4 billion possible cells, a spreadsheet may have only 40 non-empty cells. There is not even room in memory to store 4 billion null pointers.

So what is a memory efficient way to model the cell storage of a spreadsheet? A way that is also CPU efficient when the sheet is addressed by (row, column)?

I mention this because the solution is likely to involve arrays or collections of pointers to cells.

By the way, Dan Bricklin had to do it in assembler language, without a stack or a heap, on a computer with only 4KB-64KB of memory. But Dan's program was marvelously successful.
 
  • Like
Likes yungman

1. What is polymorphism in relation to pointer to array?

Polymorphism refers to the ability to have different forms or behaviors. In the context of pointers to arrays, polymorphism allows for the same pointer to point to different types of arrays, depending on the situation.

2. How does polymorphism using pointer to array work?

Polymorphism using pointer to array works by using a base class pointer to point to an array of derived class objects. This allows for the use of common methods and properties, while also being able to access specific behaviors of the derived class objects.

3. What are the benefits of using polymorphism with pointer to array?

Using polymorphism with pointer to array allows for more flexibility and reusability in code. It also helps to avoid code duplication and improves the overall organization and readability of the code.

4. Can you give an example of polymorphism using pointer to array?

An example of polymorphism using pointer to array could be a program that manages different shapes, such as circles, squares, and triangles. The base class would be "shape" and the derived classes would be "circle", "square", and "triangle". The pointer to array could then be used to access the common methods and properties of the shapes, while also being able to access the specific behaviors of each shape.

5. Are there any limitations to using polymorphism with pointer to array?

One limitation of using polymorphism with pointer to array is that it can only be used with objects of the same derived class. It cannot be used with objects of different derived classes. Additionally, if the base class does not have a virtual function, the derived class objects may not be able to override it, limiting the use of polymorphism.

Similar threads

  • Programming and Computer Science
2
Replies
36
Views
2K
  • Programming and Computer Science
Replies
17
Views
1K
  • Programming and Computer Science
Replies
5
Views
884
  • Programming and Computer Science
Replies
4
Views
1K
  • Programming and Computer Science
Replies
20
Views
1K
  • Programming and Computer Science
Replies
1
Views
646
  • Programming and Computer Science
Replies
6
Views
921
  • Programming and Computer Science
Replies
3
Views
1K
  • Programming and Computer Science
Replies
5
Views
817
  • Programming and Computer Science
Replies
7
Views
1K
Back
Top