2

I'm still trying to learn C++ and my first approach came from a non object side of C. So I want to redo my structs and make use of the class data structure. I've come up with this.

In Gradebook.h

class Gradebook {
public:
//default constructor, initializes variables in private
Gradebook();
//accessor constructor, access members in private
private:
struct Student {
    int student_id;
    int count_student;
    string last;
    string first;
    };
struct Course {
    int course_id;
    int count_course;
    string name;
    Student *students;
    };
};

In my Gradebook.cpp

Gradebook::Gradebook() {

 Course *courses = new Course;
 courses->students = new Student;

 courses->count_course = 0;
 courses->course_id = 0;

 courses->students->count_student = 0;
 courses->students->student_id = 0;

}

My Design

I want to dynamically create x_amount to Students and x_amount of Courses.

Problem

I don't understand how to access my struct so I can start to add courses and students inside my struct.

I believe I can do the rest if I can try to access my struct and manipulate the members inside it. I've tried:

void Gradebook::newCourse(Course *courses) {

  //do stuff

}

When I try to compile it I get all kinds of errors:

In file included from gradebook.cpp:2:
./gradebook.h:9:18: error: C++ requires a type specifier for all declarations
        void newCourse(&Course);

gradebook.cpp:39:17: error: out-of-line definition of 'newCourse' does not match any
      declaration in 'Gradebook'
void Gradebook::newCourse(Course *courses) {


2 errors generated.
In file included from main.cpp:4:
./gradebook.h:9:18: error: C++ requires a type specifier for all declarations
        void newCourse(&Course);

Any help for this noob is appreciated. Thanks in advance!

Marius Bancila
  • 16,053
  • 9
  • 49
  • 91
user2816227
  • 173
  • 2
  • 13
  • Why are Student and Corse *inside* Gradebook class -- are they not seperate objects by themselves? – Soren Apr 18 '14 at 20:23

2 Answers2

0

The Student and Course are declared as private structs, so you cannot access them directly.

You have three options;

  1. Make the seperate first class objects as their own classes.
  2. Make the Gradebook have interfaces which can create and manipulate the Students and Courses.
  3. Make the Students and Course public structs in the Gradebook
Soren
  • 14,402
  • 4
  • 41
  • 67
  • how can I manipulate Students and Courses if they are outside my Class? – user2816227 Apr 18 '14 at 20:27
  • The same way as you do it when they are inside. – Soren Apr 18 '14 at 20:30
  • Putting them inside the "private" section, does nothing to the object other than telling the compiler that only code belonging to Gradebook can access them. – Soren Apr 18 '14 at 20:32
  • isn't that good coding practice to put them inside the Gradebook class? – user2816227 Apr 18 '14 at 20:44
  • @Soren You should probably include in your answer the fact that he has no data members in his `Gradebook` class and his constructor is all wrong. – jliv902 Apr 18 '14 at 20:44
  • @jliv902 -- while that is a good point, I kind of assume that he had just cut back the code to what was minimal to ask his question... – Soren Apr 18 '14 at 20:50
  • @user2816227 -- It depends on what you are trying to do. If Students are never known outside Gradebook, then yes they should be private -- but intuitively Students and Courses can exist on their own -- you can have a student who have taken no course, and have no grades -- so I would suggest they are separate entities. – Soren Apr 18 '14 at 20:52
  • @jiv902, Again I am still new to C++, having learned C a few weeks ago. So I have a basic understanding on whats going on. But, everything I've googled hasn't come up with how to create class that is dynamic meaning the class grows as I add more information. In C I can create a struct using dynamic allocation and add information to it using. course[i].course_id...etc. I haven't found a way to do this in C++. So I reverted back to C methodology. – user2816227 Apr 18 '14 at 20:52
  • Eventually I want to be able to compare so I can send &course[i] into a function. Where i now will have its own information of student data etc... C seems to be easier, but I want to do it using C++ idioms. – user2816227 Apr 18 '14 at 20:56
0

Your whole design could use some work.

Your structs should initialize themselves. It also makes sense for them to be outside of Gradebook.

Here is a sample "C++ way" of doing this:

First note that std::vector is a dynamic array. Rather than needlessly managing your own memory, use std::vector instead. To use a std::vector, you need to put #include <vector> somewhere at the top of your file.

For Student, we removed the count_student variable. A container should keep track of the number of students. Student also initializes its own values now via a constructor. Notice how I am using a constructor initialization list.

struct Student 
{
    Student () ;

    int student_id;
    std::string first;
    std::string last;
};

Student::Student () : student_id (0)
{
}

We do similar things for Course. Once again, the important thing here is that Course is initializing and managing its own variables.

struct Course 
{
    Course () ;

    int course_id;
    std::string name;
    std::vector <Student> students;
};

Course::Course () : course_id (0)
{
}

The Gradebook class is now simplified. Notice how NewCourse takes a reference instead of a pointer.

class Gradebook {
public:
    Gradebook () ;

    void NewCourse (const Course &course) ;

private:
    std::vector <Course> courses;
};

Gradebook::Gradebook ()
{
}

void Gradebook::NewCourse (const Course &course)
{
    courses.push_back (course) ;
}

Other thoughts

I would probably take out the std::vector <Student> students; from Course. While yes, a course may have many students, a student may also take many courses. This many-to-many relationship may cause headaches or it may not.

One way of handling this is described in this link. Another way would be to have to structure that stores pairs of students and courses.

Update

Here is the function signature for std::vector::push_back:

void push_back (const value_type& val);

As you can see, the function returns void, so you can't do something like courses.push_back(id_number)->course_id. This function only inserts an object into your vector.

Here is an example of how to use std::vector with the Student struct. First, just to make things a little easier, I'll add a new constructor to Student. Please note that I also changed student_id to just id to minimize redundancy.

struct Student 
{
    Student () ;
    Student (const int id, const std::string &first, const std::string &last) ;

    int id;
    std::string first;
    std::string last;
};

Student::Student () : id (0)
{
}

Student::Student (const int id, const std::string &first, const std::string &last)
    : id (id), first (first), last (last)
{
}

Here's an example of how to use a vector.

int main (void)
{
    // Create some students.
    Student s1 (1, "Bob", "Smith") ;
    Student s2 (2, "Katy", "Adams") ;
    Student s3 (3, "Mary", "Williams") ;

    // Create vector of students.
    std::vector <Student> students ;

    // Insert the students into the vector.
    students.push_back (s1) ;
    students.push_back (s2) ;
    students.push_back (s3) ;

    // Go through the students and print out data.
    for (unsigned n = 0; n < students.size (); ++n) {
        // Grab a reference to one of the students.
        Student &student = students [n] ; 

        // Print out information, be sure to #include <iostream> somewhere.
        std::cout << "ID: " << student.id
            << ", Name: " << student.first << " " << student.last << "\n" ;
    }

    // To update Bob's name to Rob.
    students [0].first = "Rob" ;

    return 0 ;
}
Community
  • 1
  • 1
jliv902
  • 1,648
  • 1
  • 12
  • 21
  • @jiv902, I see, I was wondering how to use vector on a struct. I've tried using vector courses; then passing it to a function then it said it was unknown. So when I update a course id i would use courses.push_back(id_number)->course_id? I mean is this how its done? I understand this new concept your giving me but I also now have lots of questions on how courses.push_back updates course_id. Do you mind explaining it a bit more? – user2816227 Apr 18 '14 at 21:31
  • Also, I've tried your code and I got this following error. "error: definition of implicitly declared default constructor" in reference to Course::Course and Student:Student – user2816227 Apr 18 '14 at 21:43
  • @user2816227 You probably forgot to declare the constructor in the class definition itself. Also make sure you didn't skip any semi-colons or parenthesis. See [this](http://stackoverflow.com/questions/5765780/can-anyone-help-me-understand-this-error-definition-of-implicitly-declared-cl) for more information. I also updated my answer a little. Hopefully it explains a bit more about what you want. – jliv902 Apr 18 '14 at 21:54
  • Thank you so much for that piece of code. While I have more questions that I have answers. Now I have a place to start learning. I'm reading over your links and googling all kinds of things. I appreciate it. – user2816227 Apr 18 '14 at 22:17