tags:

views:

266

answers:

7

Edit again: I think I get it now. All I need to do then is use the current class colon the class I want to be able to access? Person : Student, or person : teacher Is that correct? Thank everyone for the help, I really appreciate it. This will help me learn what is OO and what is not. I really appreciate that.

I'm currently trying to learn the ins and outs of object oriented programming. Currently I have a new object that's something like the following:

class student
{
    int grade; //0 - 100 as opposed to the characters A, B, C, etc.
    string teacher; //For the teacher of the class the student is in.

}

class teacher
{ 
    int courseAverage;
    string name; 
    //teacher.name would correspond to the teacher in the student class.
}

class Program
{
    student Jim;
    Jim = new student();
    teacher John;
    John = new teacher();
}

static void grades()
{
    Jim.grade = 100;
}

static void teacher()
{
    Jim.teacher = "John Smith";
}

static void average()
{
    int average; //For the sake of simplicity I'll leave the average at an int.
    average = (Jim.grade + Sue.grade + Sally.grade + Robert.grade) / 4;
    /*A loop would be set before the average variable to 
    ensure that only students of John would be counted in this.*/

}

static void teacheraverage()
{
    John.courseAverage = average;//from the average method.
}

EDIT:

What I would like to do is modify the information from another class. However, I would like to modify the information from the Jim student in a method from within the program class. A method to compute the average of grades for the students who have the given teacher.

Also, the only reason I use static in these is because that is the only way I have managed to access variables across methods. I tried using static methods to use the methods across classes with no success. Is there another way to do this?

I would like to use the Jim student in multiple methods. One that will set Jim's grade, and another that will set the teacher. I would like to use different methods in this case so that I can learn how it is done.

Thank you in advance.

Okay, it looks like my understanding wasn't correct. I am going to try the methods within the class approach. Thank you all for the help.

+3  A: 

Well, at least three ways.

  1. Make grades and teacher methods of the Student class:


public class Student
{
    int grade; //0 - 100 as opposed to the characters A, B, C, etc.
    string teacher; //For the teacher of the class the student is in.

    public void SetGrades()
    {
        grade = 100;
    }

    public void SetTeacher()
    {
        teacher = "John Smith";
    }
}

class Program
{
    public static void Main()
    {
        Student Jim;
        Jim = new Student();
        Jim.SetTeacher();
        Jim.SetGrades();
    }
}

or 2. Pass the student to the methods:


class Program
{
    public static void Main()
    {
        Student Jim;
        Jim = new Student();
        grades(Jim);
        teacher(Jim);
    }

    static void grades(Student student)
    {
        student.grade = 100;
    }

    static void teacher(Student student)
    {
        student.teacher = "John Smith";
    }
}

or 3. Use Jim as a variable in the Program class, so you don't actually have to pass it to anything


class Program
{
    static Student Jim;

    public static void Main()
    {
        Jim = new Student();
        grades();
        teacher();
    }

    static void grades()
    {
        Jim.grade = 100;
    }

    static void teacher()
    {
        Jim.teacher = "John Smith";
    }
}


Note that in all examples I made the Student class have an uppercase S in its name, to distinguish it from the parameter and any local variables you might have.

It's important to know the differences.

In the first solution, you ask the object itself to set the grades and the teacher. If these are operations you do a lot, they probably belong in the class itself, instead of being operations outside.

In the second solution, you pass around the student. This allows you to easily work with multiple students, since the code isn't hardwired to work with a single object.

In the third solution, you don't have to pass anything around, but your code is now locked to only working with one student at a time, in the Jim field.

Personally I would work out a variation of the first solution, only a bit more flexible in terms of what grade it would set, and which teacher. Probably using properties (which you should also look more into.)

Lasse V. Karlsen
+5  A: 

Since you're using C#, and assuming you're using .NET 3.5, your class would probably be looking something like this:

public class Student
{
    public int Grade { get; set; }
    public string Teacher { get; set; }
}

Grade and Teacher are automatic properties, which are roughly equivalent to getters and setters in Java, which would be methods. Properties in C# are essentially shortcuts to get and set local members of a class.

Your usage of the above class would looks something like this:

public class Program
{
    // creates a new Student object with the properties Grade and Teacher set.
    Student s = new Student() { Grade = 100, Teacher = "John Smith" }

    Console.Write(s.Grade); // outputs 100
    Console.Write(s.Teacher); // outputs John Smith
}

Is this what you're looking for?

steve_c
Not exactly. What I would like to do is modify the information from another class. However, I would like to modify the information from the Jim student in a method from within the program class. A method to compute the average of grades for the students who have the given teacher.
Xesaniel
You can modify the information, Grade and Teacher, using the properties just like they're variables. s.Grade = 50;, s.Teacher = "Jane Doe";
steve_c
A: 

Okay, there's a basic misunderstanding here. Your methods are associated with the class. What you've got are basically structs wih some functions that use them; not wrong, but not OO at all.

What you really want is something like this (in hopefully good expository pseudocode):

class Person
  name : String
  Person(namearg: String) -- your constructor
    name = namearg;
  end
end

class Student :: Person -- read :: as "is a kind of"
  Student(namearg : String)
    super(namearg) -- calls the Person ctor
  end
  -- more stuff will go in here
end
-- Teacher looks much the same

class Course
  courseName : String
  teacher : Teacher
  students : list of Student
  Course(namearg : string)
    courseName = namearg 
  end
  addStudent(s : student)
    students.append(s) -- add student to the end of the list
  end
  -- and so on.
end

The point is that a class knows everything there is to know about the thing it describes: both the data it uses and the operations that can be performed.

Charlie Martin
Question was asked using C# examples given the beginner level of the question in regard to .net using the VB syntax will be confusing and not helpful.
trampster
@Daniel: this is pseudocode, and Charlie is correct
Steven A. Lowe
I've been working on this for a while trying to wrap my head around it. Could anyone explain this a little bit? I probably only need a little push to get me going.
Xesaniel
Charlie is right, but his choice of presenting the questioner with a new problem (learning to parse a Ruby-like syntax invented on the fly) is probably not helpful.
Daniel Earwicker
I Agree this is the correct answer would someone with the required powers edit the answer to use C#. Then it can be voted up.
trampster
The syntax is actually more Pascal-like; if someone wants to send me C# I'll enter it. I dn't know C#.
Charlie Martin
A: 

lassevk does a good job of answering your question - which is basically, how do you access the Student instance named Jim across multiple methods.

I'd like to point out, though, that you're doing procedural code here. Not that there's necessarily anything wrong with that - just that you're not really "getting" OO here.

A quick, 2 minute example of an OO-ish way:

class Student {
   public string Name { get; private set; }

   public Student(string name) {
      if (string.IsNullOrEmpty(name)) throw new ArgumentException();
      this.Name = name;
   }
}

class Teacher {
   public string Name { get; private set; }

   public List<Course> Courses { get; private set; }

   public Grade GetAverageCourseGrade() {
       int totalCourseGrade;
       foreach (Course course in this.Courses) {
          totalCourseGrade += course.GetAverageGrade().Value;
       }
       return new Grade(totalCourseGrade / this.Courses.Count);
   }

   public Teacher(string name) {
       if (string.IsNullOrEmpty(name)) throw new ArgumentException();
       this.Name = name;
       this.Courses = new List<Course>();
   }
}

class Course {
   public string Name { get; private set; }

   public IEnumerable<Student, Grade> StudentGrades { get; private set; }

   public Grade GetAverageGrade() {
      int totalGrade;
      // could use LINQ, but I'll make it slightly more explicit
      foreach (KeyValuePair<Student, Grade> studentGrade in this.StudentGrades) {
         Grade grade = kvp.Value;
         totalGrade += grade.Value;
      }
      return new Grade(totalGrade / this.StudentGrades.Count());
   }

   public Course(string name) {
       if (string.IsNullOrEmpty(name)) throw new ArgumentException();
       this.Name = name;
       this.StudentGrades = new Dictionary<Student, Grade>();
   }
}

class Grade {
   public int Value { get; private set; }

   public char Letter { 
       get {
          switch (this.Value / 10) {
             case 10: case 9:
               return 'A';
             case 8:
               return 'B';
             case 7:
               return 'C';
             case 6:
               return 'D';
             default:
               return 'F';
          }
       }
   }

   public Grade(int value) {
      if (value < 0 || value > 100) throw new ArgumentOutOfRangeException();
      this.Value = value;
   }
}

class Program {
   static int Main(string[] args) {
      Teacher john = new Teacher("John Smith");

      Course cs101 = new Course("Computer Science 101");
      john.Courses.Add(cs101);

      Student mark = new Student("Mark Brackett");
      Student xesaniel = new Student("Xesaniel");

      cs101.Students.Add(mark, new Grade(90));
      cs101.Students.Add(xesaniel, new Grade(95));

      Console.WriteLine(john.GetAverageCourseGrade());
   }
}

There's a lot of ceremony and noise there, but the important bit is that Teacher and Course know how to calculate their own average grades and validate/enforce their own internal state. The Main method is really only responsible for coordinating the setup and any interactions between the classes.

Technically, a lot of the relations here are bidirectional - eg., a teacher has many courses, and a course has a single teacher. But, a bidirectional relationship can be a PITA to manage - and there's no compelling reason for it here.

Mark Brackett
A: 

Your model is oversimplified and underspecified. But let's ignore that for the moment ;-)

in the examples below i am also ignoring the details of properties and stubbing the constructors so as not to confuse the main modeling issue

Student and Teacher are both People (as Charlie Martin and others pointed out)

//people have names
public class Person
{
    public Person(string _name)
    {
        Name = _name;
    }
    public string Name;
}

A Student is a Person, and has a grade and a teacher

//students are people with a grade and a teacher
public class Student : Person
{
    public Student(string _name, int _grade, 
        Teacher _teacher) : base(_name)
    {
        Grade = _grade;
        Teacher = _teacher;
        Teacher.Students.Add(this);  //add to the teacher's collection
    }
    public int Grade;
    public Teacher Teacher;
}

Teachers are people, with a course average grade and a set of Students.

public class Teacher : Person
{
    public Teacher(string _name) : base(_name)
    {
    }
    public int CourseAverage;
    public IList<Student> Students = new List<Student>();
    public void ComputeAverageGrade()
    {
        int sum = 0;
        foreach(Student s in Students)
        {
            sum += s.Grade;
        }
        CourseAverage = sum / Students.Count;
    }
}

In your example you have some students and compute the average grade

public class Program
{
    public static void Main(string [] args)
    {
        Teacher JohnSmith = new Teacher("John Smith");

        Student Jim = new Student("Jim",100,JohnSmith);
        Student Sue = new Student("Sue",90,JohnSmith);
        Student Sally = new Student("Sally",70,JohnSmith);
        Student Robert = new Student("Robert",100,JohnSmith);

        //add our resident overachiever
        Student JonSkeet = new Student("Jon Skeet",150,JohnSmith);

        JohnSmith.ComputeAverageGrade();

        Console.WriteLine("Course Average for " + JohnSmith.Name + " is " +
            JohnSmith.CourseAverage.ToString());
    }
}

In a more realistic model, each student would likely be taking more than one course, and each teacher would probably be teaching more than one course, so you would need to model the Courses. Courses only exist for the duration of a Semester or a Quarter, etc.

Steven A. Lowe
A: 

Try to think of a class as the blue print for making a machine. An object is a machine. When you're using it, you don't care about how it works inside. You just use the various levers and switches on the outside to control it, and LEDs that tell you answers, and so on. It's a "black box" to you.

The levers and switches are methods and properties. They expose a "user interface" for interacting with the object.

The code inside the methods is internal. How it works is a secret. This makes the object simpler to use (if it is well designed). The fields that ultimately store information are also secrets. They are not directly accessed by code outside the class's methods.

public class Student
{
    // Notice how these details are private
    private List<Subjects> _subjects = new List<Subjects>();
    private DateTime _started;

    // A property that only has a 'getter' because the value shouldn't be modified
    public DateTime Started
    {
        get { return _started; }
    }

    // Methods carry out actions. This one calls on to a method in another object.
    public void Enroll(Subject s)
    {
        if (_subjects.Contains(s))
            throw new Exception("Already studying that course");

        s.RegisterStudent(this);
        _subjects.Add(s); 
    }

    public void Flunk(Subject s)
    {
        if (!_subjects.Contains(s))
            throw new Exception("Can't flunk that subject, not studying it");

        s.RemoveStudent(this);
        _subjects.Remove(s);
    }
}

If you follow this approach, you're on your way to object orientation. You still have a lot of fun things to learn about - exception safety, the abuse of inheritance, loose coupling...

Daniel Earwicker
+1  A: 

You're still missing the essential point: a class associates the data with its methods. So the method that sets Jim's teacher is part of the Student class, as is the method that sets Jim's grade.

Think of it in natural language first. "Jim is a student; students have names, stident ID numbers, and classes. Classes have teachers and classrooms. Students receive grades for each class at the end of the term."

So we have a class Student. Student, when you create an object from it, needs the students name and student ID, so the "constructor" needs to be something with a name string and a student ID -- call it a String too -- to initialize it. I don't know C#, so I'll make a pseudocde with braces...

class Student {
    String name;
    String studentID;
    Course crsList = List<Course>; // "list of courses."
    Student(String name, String studentID ){
        // Make a new student, the "constructor"
        this.name = name;
        this.studentID = studentID;
    }
    addCourse(Course c){
        // Add a course to the student's list
        this.crsList.append(c); // Adds c to end of crsList
    }
}

This says "A Student has a name and ID, and we can add classes to their collection of classes."

class Teacher {
    String name;
    Course crsList = List<Course>;
    Teacher(String name){
        this.name = name;
    }
    // ... more methods here.
}

But we observe that teachers and students are both kinds of people, so we "refactor" this to put the common piece together

class Person {
    String name;
    Person(String name){
        this.name = name;
    }
    // ... more methods
}

Now we change Teacher and Student so we say

class Student : Person {
    String studentID;
    Student(String name, String studentID){
        // Now we need to initialize the Person part
        super(name);
        // and the special Student part
        this.studentID = studentID;
    }
}

which now says "a Student is a kind of Person who has an additional student ID, and who we can add classes to."

You'd go on to define "addClass" for Teach, but as part of the Teacher class. Why? Because adding a class for a teacher means something different than adding one for a student. You'd add a method to Student that takes a Course and a Grade, finds the Course and assigns he grade somehow. (Pop quiz: is a Grade part of a Course or part of a Student?)

Charlie Martin
That is incredibly clear, still a little rough on the edges for me but now I get the extremely basic concept. As far as the pop-quiz goes, I would assume that it would be a part of the student as the student would get grades for a course. courses have the student's grades, correct?
Xesaniel
Yup. We'd need more use cases to know exactly how (do we have a requirement coming to see, eg, what the average grade in a session of a course will be) but my first thought is that there would be an association between a Student and a Course instance; ...
Charlie Martin
... and you would have an "assignGrade" method that sets the grade for the student against the course. (If you had the requirement to tabulate against courses, you'd use the association to find it from Student.)
Charlie Martin