Reputation: 62
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?
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.
Okay, it looks like my understanding wasn't correct. I am going to try the methods within the class approach.
Upvotes: 1
Views: 3220
Reputation: 112424
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?)
Upvotes: 1
Reputation: 116744
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...
Upvotes: 0
Reputation: 61262
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.
Upvotes: 0
Reputation: 85685
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.
Upvotes: 1
Reputation: 391704
Well, at least three ways.
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.)
Upvotes: 3
Reputation: 112424
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.
Upvotes: 0
Reputation: 6265
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?
Upvotes: 5