My assignment for class was to create a Student ADT. |
An abstract data type is a black box, with the data completely hidden.
A really good example of an ADT implementation in C is FILE*. You don't really care what's in a FILE, you only care that you use it with fopen, fclose, fread, fwrite, fseek, ftell, ...
A not so good example of an ADT implemented in C is string. The implementation is exposed (char*), but that asside, you can use it with strdup, strcat, strcpy, strstr, strchr, ...
There are some problems with your implementation:
1. The implementation is exposed.
2. You can use C++ language features to enforce ADT principles.
So, in C++, I'd expect your ADT to look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
#include <string>
#include <istream>
#include <ostream>
class Student
{
friend std::ostream& operator<<(std::ostream&, const Student&);
friend std::istream& operator>>(std::istream&, Student&);
public:
const std::string& getFirstName() const;
const std::string& getLastName() const;
const std::string& getStudentNumber() const;
int getAssignGrades() const;
int getExamGrade() const;
void setFfirstName(const std::string&);
void setLastName(const std::string&);
void setStudentNumber(const std::string&);
void assignGrade(int idx);
void assignGrade(int idx, int value);
void setExamGrade(int);
// optionally
static Student* create();
static void destroy(Student*);
private:
std::string firstName;
std::string lastName;
std::string studentNumber;
std::vector<int> assignGrades;
int examGrade;
};
std::ostream& operator<<(std::ostream&, const Student&);
std::istream& operator>>(std::istream&, Student&);
|
I've replaced C strings with the standard string, and the int array with a standard int container.
The client code would then look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
#include <iostream>
#include <cstdlib>
#include <cstring>
#include "Student.h"
int main()
{
Student* testStudent = Student::create();
testStudent->setFirstName("Ashley");
testStudent->setLastName("Armstrong");
testStudent->setStudentNumber("12345678");
for (int i = 0; i < 10; i++)
{
testStudent->assignGrade(i * 10);
}
testStudent->setExamGrade(95);
std::cout << (*testStudent) << std::endl;
testStudent->assignGrade(2, 5);
std::cout << (*testStudent) << std::endl;
// ... and so on
Student::destroy(testStudent);
testStudent = std::nullptr;
}
|
As for the implementation of new/delete
1 2 3 4 5 6 7 8 9
|
Student* Student::create()
{
return new Student();
}
Student::destory(Student* obj)
{
delete obj;
}
|
Of course those wrappers, create/destroy are optional. But even if you needed to keep them, these days you'd use a smart pointer that does the delete for you:
1 2 3 4 5 6 7 8
|
#include "Student.h"
#include <memory>
int main()
{
std::unique_ptr<Student> testStudent = testStudent(Student::create(), Student::destroy);
// ... don't call destroy when you're done, the smart pointer does it for you.
}
|