QList pointer function to abstract class - c++

I feel dumb for asking this question because it seems like it would be simple but I don't know how to do it and I can't find it anywhere on the internet. I'm trying to make a function that will return a QList to standard output, the pointer to the abstract class is confusing me. The AbstractStudent class generates an instance of another class Student. here is the function:
QList<AbstractStudent*>* StudentList::returnList() const{
}

A list which stores pointers of an abstract class will be able to store pointers to any sub class of that abstract class.
Think of the following:
AbstractStudent.h:
class AbstractStudent
{
// ...
};
Student.h:
class Student : public AbstractStudent
{
// ...
};
Any other class .cpp:
QList< AbstractStudent* > studentList;
// Each of the following works:
AbstractStudent* student1 = new Student( /* ... */ );
studentList.append( student1 );
Student* student2 = new Student( /* ... */ );
studentList.append( student2 );
Student* student3 = new Student( /* ... */ );
AbstractStudent* student3_1 = student3;
studentList.append( student3 );
I am however a bit confused of your last sentence, claiming that AbstractStudent generates Student objects. I would have expected that Student inherits AbstractStudent and some other class generates Student objects, like in my example.

Related

Accessing subclass methods in array of pointers

I've been having trouble accessing the "getDegreeProgram()" method in my objects that are set to my array of pointers; all of my baseclass methods are working, but for some reason, my subclass methods aren't even visible. I'm suspecting that I don't have the syntax right, and its converting all of my subclass objects to the baseclass of student.
roster.h:
class roster {
private:
student** classRosterArray; //array of pointers
roster.cpp function that creates my objects and sets them to the array of pointers
void roster::createStudentObject() {
classRosterArray = new student *[5]; //array of pointers
if (degreeProgramInput == "NETWORK") {
classRosterArray[rosterCounter] = new networkStudent();
}
else if (degreeProgramInput == "SECURITY") {
classRosterArray[rosterCounter] = new securityStudent();
}
else classRosterArray[rosterCounter] = new softwareStudent();
}
student.h subclasses in question (they're subclasses of my baseclass "student")
class networkStudent:public student {
private:
int networkDegree;
public:
int getDegreeProgram();
networkStudent();
};
class securityStudent:public student {
private:
int securityDegree;
public:
int getDegreeProgram();
securityStudent();
};
class softwareStudent:public student {
private:
int softwareDegree;
public:
int getDegreeProgram();
softwareStudent();
};
As far as I understood, you are trying to access the elements of classRosterArray and trying to call getDegreeProgram().
For this problem, Make the getDegreeProgram() virtual function.
student.h
class student {
...
public:
virtual int getDegreeProgram() = 0; // pure virtual function
};
Subclasses of student
class networkStudent:public student {
private:
int networkDegree;
public:
virtual int getDegreeProgram();
networkStudent();
};
class securityStudent:public student {
private:
int securityDegree;
public:
virtual int getDegreeProgram();
securityStudent();
};
class softwareStudent:public student {
private:
int softwareDegree;
public:
virtual int getDegreeProgram();
softwareStudent();
};
Suggestion:
In this case, Because getDegreeProgram() seems to be a getter function, I think you should declare it as a const function.
Edit:
As rightly said by Richard, In C++ 11, override keyword was introduced for this purpose for the sub classes. So, instead of writing virtual int getDegreeProgram();, you could write int getDegreeProgram() override; also.
There are two you ways you can go about it.
Runtime Polymorphism - This method will require less code refactoring but at the cost of runtime. Each instance of a polymorphic class will have a pointer(vptr) to a table(vtable) of pointers to the different versions of the virtual function. This table will be used for finding the right version of the virtual function at runtime.
You can achieve runtime polymorphism here by making the getDegreeProgram function virtual in base class ie., Student and override it in derived classes ie., securityStudent, networkStudent and softwareStudent.
class Student {
...
public:
virtual int getDegreeProgram() = 0; // notice the virtual keyword and 0 at the end.
// 0 is for saying that it is pure virtual, meaning
// we don't have any definition for this function in
// this class. Such a class is also called as
// abstract class
...
}
class securityStudent : Student {
...
public:
int getDegreeProgram() override
{
// do the stuff you want to do
}
...
}
// driver stub
...
Student *student;
securityStudent sStudent;
networkStudent nStudent;
.
.
student = &sStudent;
student->getDegreeProgram(); // calls security student implementation of getDegreeProgram
student = &nStudent;
student->getDegreeProgram(); // calls network student implementation of getDegreeProgram
...
Static Polymorphism or CRTP or Simulated Dynamic Binding - This method does the same thing as above but with the advantage of knowing the type at compile time by means of some casting magic (below). Even this approach has its limitation like kludgy syntax and some amount of refactoring which is a lot more than in the 1st case and lack of readability due to terseness of templates etc.
The trick here is to get the derived class' information at compile time and typecast the this pointer of the base class to that of the derived class. :-)
template <typename StudentType>
class Student {
...
public:
int getDegreeProgram()
{
return (static_cast<StudentType*>(this))->getDegreeProgramImpl();
}
...
}
class securityStudent : public Student<securityStudent> {
...
public:
int getDegreeProgramImpl()
{
// write your specifc implementation here
}
...
}
// driver stub
...
securityStudent sStudent;
networkStudent nStudent;
.
.
sStudent.getDegreeProgram(); // calls security student implementation of getDegreeProgram
nStudent.getDegreeProgram(); // calls network student implementation of getDegreeProgram
...

Classes and subclasses - sending data from derived class to primary class

I'm trying to send data (fishname) from the class "Fish" to the primary class "Animal". I made an object, and tried to access the subclass function to send the data from the subclass to the primary class.
My goal: Send whatever I write in the readFish() to Animal 's private name char.
Code:
#include <iostream>
using namespace std;
const int STRLEN = 32;
class Animal {
private:
char name[STRLEN];
public:
Animal() { }
Animal(char animalname) { name[STRLEN] = animalname; }
};
class AnimalInWater : public Animal {
private:
public:
AnimalInWater() { }
};
class Fish : public AnimalInWater {
private:
char fishname[STRLEN];
public:
void readFish() {
cout << "The name of the fish: "; cin.getline(fishname, STRLEN);
Animal(fishname); // Is supposed to use the constructor seen in Animal class
}
};
int main() {
Animal a1;
d1.readFish(); // readFish() is in the Fish class, which is under AnimalInWater which is under Animal.
// In other words; the readFish() function is the granddaughter class of Animal.
return 0;
}
I made an object, and tried to access the subclass function to send the data from the subclass to the primary class.
You're talking about classes as though they were objects. If you have an instance of Fish, then it is an instance of AnimalInWater and also of Animal at the same time.
If you want readFish() to assign some value to name, then just assign it to name in that method in the Fish class.
Looking at this, piece by piece.
The variable name is an array of char and has STRLEN slots.
The slots are numbered from 0 to STRLEN-1.
The expression name[0] represents the first slot.
The expression name[STRLEN] represents one past the end of the array.
The variable animalname is a single character.
The constructor is placing the value inside animalname to the slot name[STRLEN], which is beyond the array.

Classes with Arrays using other class objects

I have two completed classes at the moment, the Teacher and Student classes have default definitions.
Right now I am trying to figure out the Classroom and School classes. The Classroom class is supposed to hold a Teacher and an array of 35 Student objects.
The School class is supposed to contain an array of 100 Classroom objects.
How do I do this, I sort of know how to initialize an array in a class but I'm not sure how to achieve this using the objects of another class?
class Teacher
{
private:
string last;
string first;
int gradeLevel;
public:
Teacher();
};
Teacher::Teacher()
{
last = "AAAA";
first = "BBBB";
gradeLevel = 0;
}
class Student
{
private:
string studLast;
string studFirst;
public:
Student();
};
Student::Student()
{
studLast = "AAAA";
studFirst = "BBBB";
}
class Classroom
{
};
class School
{
};
For example:
class Classroom
{
private:
Teacher t; // create a teacher
Student s[35]; // create an array of 35 students
...
};
class School
{
private:
Classroom rooms[100]; // create an array of 100 rooms
...
};
What you want to do here is create a Teacher, just one like you wanted, and then create an array of Student objects, which if you didn't know is done like Student students[35];. Then to the School object which is just an array of Classroom objects. Here is the full code:
class Classroom
{
private:
Teacher teacher;
Student students[35];
public:
Classroom();
};
Classroom::Classroom()
{
;
}
class School
{
private:
Classroom classrooms[100];
public:
School();
};
School::School()
{
;
}
Note: all of the items in the arrays are initialized when you write something like Student students[35];. You can check this by doing cout << this->stduents[12].studLast << endl;

Creating an object that is part of multiple classes

I am trying to build a program where I wanted to create an object that is part of two classes.
I have the class Student and then I have a class for Node. And I want to create an object that is at the same time a Student and a Node. I tried doing this:
Student James;
James = new Node;
But that doesn't work.
Any help on how to do this? Thanks.
Use inheritance: http://en.wikipedia.org/wiki/Inheritance_%28computer_science%29
class Node {
//....
}
class Student : public Node {
//....
}
Student James;
You can treat object James as Node via pointer to base object:
Node * p = &James;
What you're looking for is multiple inheritance:
class MyClass : public Student, public Node
{
// ...
};
MyClass James;
You may want to read up on this feature of C++, it's not without its pitfalls.
EDIT
The question here is: what is the relation between Student and Node?
If Student is a kind of Node (e.g. you have students, teachers, etc and you all want these to behave as nodes), then you can simply inherit Student from Node:
class Student : public Node
{
// ...
};
Student James;
In this case, you can also do:
Node* James = new Student();
// do stuff with James
delete James;
If Student and Node are independent, you have to ask yourself if you really want an object that can behave as both at the same time. Perhaps you only need an object that pairs a Student and a Node:
struct MyStruct
{
Student myStudent;
Node myNode;
};
MyStruct James;
If you actually need an object that can behave as both Student and Node (even though those two things are independent) then you'll need multiple inheritance.
Use polymorphism:
Class Base
{
}
class Student : public Base
{
}
class Node : public Base
{
}
Now:
Student s;
Node n;
Base* b = &s;
b = &n;

Abstract class reference

Can i have a class
Class Room{ ~Room(); virtual cost()
=0; }
Class Hotel{ map<int, Room> rooms; /*
*/ };
will my hotel become abstract ?
Can it hold the list of concrete Room objects that are derived from Room ?
The code you have written is not valid C++. If you mean:
class Room{
~Room();
virtual int cost() =0;
};
then yes, the class is abstract. You cannot then create a map like this:
map <int, Room> rooms;
but you can like this:
map <int, Room *> rooms;
Then assuming you have a class SingleRoom that is derived from Room and implements cost(), you can say:
rooms.insert( make_pair( 101, new SingleRoom ) );
Also, please note that abstract classes must have virtual destructors.
What you probably want is that the Hotel can store different kinds of rooms.
In that case the map in the hotel needs to store pointers to rooms rather than rooms itself, like this:
class Hotel
{
std::map<int,Room *> roomMap; // maps room numbers to rooms
};
In this example I used a map to map the room numbers to pointers pointing to the room.
If we would have stored Rooms instead of Room-pointers, then this wouldn't simply compile since we can't instantiate a Room by itself.
Notice that if you store Room-pointers, there should also be somebody that delete's the rooms afterwards. Give Room a virtual destructor (like Neil already pointed out) and just delete the rooms in the destructor of Hotel.
class Hotel
{
public:
void AddRoom()
{
m_Rooms.insert( std::make_pair( 10, new Room )); // Remember to delete
}
void AddNicerRoom()
{
m_Rooms.insert( std::make_pair( 10, new NicerRoom )); // Remember to delete
}
private:
std::map< unsigned int, HotelRoom* > m_Rooms;
}
class HotelRoom
{
public:
~HotelRoom; // Virtual Dtor
protected:
virtual int cost() = 0;
}
class Room : public HotelRoom
{
/*virtual*/ int cost()
{
// impl
}
}
class NicerRoom : public HotelRoom
{
/*virtual*/ int cost()
{
// impl
}
}
There you go. Basic example, here HotelRoom is an abstract class with Room and NicerRoom inheriting and implementing the pure virtual method cost(). This is one way you might go about doing it.
If you expand or rephrase your question so I can better understand what you are asking I'll update my answer.