-1

I'm new to C++ and I'm trying to learn how to use constructors and classes. I have the code running correctly in C through structs, but when I try to implement classes in C++ I get errors I don't know where from.

The code is meant for me to input a numerical grade and a letter, e.g. 100 F. And in return it should tell me the letter grade for the first value, and the numerical value for the letter: 100:A and 45:F. I'm sure the functions are correct and I main makes sense. The error I get says there's no matching function for Grade g; in my main.

class Grade {

public:

    int* percent;
    char* letter;
    char GRADE_MAP [11] = {'F', 'F', 'F', 'F', 'F', 'F', 'D', 'C', 'B', 'A', 'A'};

    Grade(int p, char l){
        percent = new int;
        letter = new char;
        *percent = p;
        *letter = l;
    }

    ~Grade(){
        delete percent;
        delete letter;
    }

    void setByPercent(int p){
        p = *percent;
        *letter = GRADE_MAP[p / 10];
    }

    void setByLetter(char l){
        l = *letter;
        *percent = 100 - (l - 'A') * 10 - 5;
    }

    void print(){
        printf("Grade: %d: %c \n", *percent, *letter);
    }
};


int main() {

    int percent;
    Grade g;

    printf("Enter two grades separated by a space. Use a percentage for the first and letter for the second: \n");

    scanf("%d", &percent);
    scanf("\n");

    g.setByPercent(percent);
    g.print();

    g.setByLetter(getchar());
    g.print();

    return 0;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335

2 Answers2

2

Okay, first things first: You're totally misusing dynamic memory. There is no point in dynamically allocating a single int, or single char. A pointer is at least the size of an int, if not double the size (depending on combination of CPU and OS), and for a char it's 4 or 8 times the size. Plus the indirection cost.

Also by having that GRADE_MAP defined as a regular, initialized class member, you're creating a copy of that for each and every instance.

Last but not least, the whole point of access specifiers is to yank class members away from outside hands (to some degree, you can still manipulate them by doing memory voodoo).

So let's get rid of that.

First include iostream and sstream for output

 #include <sstream>
 #include <iostream>

 class Grade {

just regular member, no dynamic

     int  percent;
     char letter;

make that static and const to move this out into the executables .rodata section

    static char const GRADE_MAP [11] = {'F', 'F', 'F', 'F', 'F', 'F', 'D', 'C', 'B', 'A', 'A'};

Static helper functions for conversion, used by setters and constructors:

    static int fromLetter(char l){
        int p = 100 - (l - 'A') * 10 - 5;
        if( 0 > p || 100 < p ){
            throw std::range_error("equivalent percentage out of range");
        }
        return p;
    }
    static char fromPercent(int p){
        if( 0 > p || 100 < p ){
            throw std::range_error("percentage out of range");
        }
        return GRADE_MAP[p / 10];
    }

Constructor should be public

public:

Use initializers here

     Grade(int p)
     : percent(p)
     , letter( fromPercent(p) )
     {}

     Grade(char l)
     : percent( fromLetter(l) )
     , letter( l )
     {}


     ~Grade(){}

You probably meant to access percent from p. The way you wrote it ignores the parameter

    void setByPercent(int p){
         percent = p;
         letter = fromPercentage(p);
    }

    void setByLetter(char l){
         letter = l;
         percent = fromLetter(l);
    }

Finally be C++ -ish and use iostream

     basic_ostringstream strstr(){
         basic_ostringstream os;
         os << "Grade: " << percent << ": " << letter;
         return os;
     }
};

int main() {

    int percent, letter;
     std::cout << "Enter two grades separated by a space. Use a percentage for the first and letter for the second:" << std::endl;
     std::cin >> percent >> letter;     

     Grade g1(percent)
     Grade g2(letter)

     std::cout << g1.strstr() << "; " << g2.strstr() << std::endl;
    return 0;
}
datenwolf
  • 159,371
  • 13
  • 185
  • 298
1

For starters these two member functions are invalid

void setByPercent(int p){
    p = *percent;
    *letter = GRADE_MAP[p / 10];
}

void setByLetter(char l){
    l = *letter;
    *percent = 100 - (l - 'A') * 10 - 5;
}

It seems you mean

void setByPercent(int p){
    *percent = p;
    *letter = GRADE_MAP[p / 10];
}

and

void setByLetter(char l){
    *letter = l;
    *percent = 100 - (l - 'A') * 10 - 5;
}

The class does not have the default constructor. So this declaration

Grade g;

is incorrect because here the default constructor that is absent shall be called.

Specify arguments for the created object for example like

Grade g( 100, 'A' );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335