Datatypes and polymorphism - c++

I have a design question. I want custom datatypes implementing an interface. For example, using templates is simply (maybe next design isn't correct -because I can do a generic class instead of the next- but clarifies my goal):
template <typename T>
class IDatatype
{
public:
virtual T getData() const = 0;
virtual void setData(T pData) = 0;
};
class MyChar: public IDatatype<char>
{
public:
void setData(char pData){...}
char getData() const{...}
private:
char _data;
};
class MyInt: public IDatatype<int>
{
public:
void setData(int pData){...}
int getData() const{...}
private:
int _data;
};
IDatatype<int> *data = new MyInt(); // parametrized interface, bad idea :(
data->getData(); // it works ok
From previous classes, it is easy to get the attribute corresponding to each _data class member. My question:
Is there any way (change design, etc.) to implement generic setter and getter in IDatatype
and for any type and thus manipulate the _data attribute of each class
without using templates in the interface?
For example:
class IDatatype
{
public:
// pure virtual getters and setters for specialized _data fields. Here is my design question.
};
class MyChar: public IDatatype
{
public:
void setData(char pData){...};
char getData(){...};
private:
char _data;
};
class MyInt: public IDatatype
{
public:
void setData(int pData){...};
int getData(){...};
private:
int _data;
};
IDatatype *intData = new MyInt(); // no parametrized interface!
intData->getData(); // how can I create this method from IDatatype?
IDatatype *charData = new MyChar();
charData->getData(); // the same here
NOTE: I have no good english, apologize for any errors :)

You could probably achieve this in 3 ways, none as elegant and error free as using a template
Define your data as a union of int/float/char in the base class and act on this union from the set/get methods of the base class. The entire VB (old VB 6) class system works on such a data type called VARIANT.
Return void * from base class and cast and use as appropriate - yuck & good luck!!.
Return the base interface reference itself from the getData which though appearing to be meaningful, has no meaning at all.
4.

Related

Trying to point a base class function pointer to a derived class function

I'm trying to implement a strategy pattern. Right now I'm making a vector of function pointers that take in a vector of ints as their type. I called this vector of function pointers "algo". I want each of the function pointers in the vector to point to a different sorting class (merge, bubble, or insertion). My class structure looks like this: Algorithm is the base class, Sort is an abstract class that inherits from Algorithm, and then Merger, Insertion, and Bubble all inherit from Sort. The problem that I'm running into right now is I can't seem to get my mergePointer pointed to the sortFunc() inside the Merger class. When I try to execute my code it says:
main.cpp:59:28: error: use of undeclared identifier 'sortFunc'
mergePointer = sortFunc();
^
I originally figured the problem was scope resolution so I added Merger:: infront of sortFunc() and I got the same error. I'm not to familiar with polymorphism and am not even sure if what I'm trying to do is possible, any thoughts?
class Algorithm{
private:
public:
vector<int> data;
static std::vector<void (*)(std::vector<int>&)> algo;
void (*activeAlgo)(std::vector<int>&);
enum SortingAlgorithms{
Merge = 0, Insertion, Bubble, Last
};
void load(){
void (*mergePointer)(vector<int>&);
mergePointer = sortFunc();
algo.push_back(mergePointer);
}
void select(SortingAlgorithms sort){
}
};
//abstracted class
class Sort: public Algorithm{
private:
public:
virtual void sortFunc() = 0; //pure virtual function
};
class Merger: public Sort{
private:
public:
void sortFunc(){
data = mergeSort(data);
print(data);
}
};
class Insertion: public Sort{
private:
public:
void sortFunc(){
printVec(data);
insertionSort(data);
printVec(data);
}
};
class Bubble: public Sort{
private:
public:
void sortFunc(){
printVector(data);
bubbleSort(data);
printVector(data);
}
};
int main(){
Sort *myAlgo;
myAlgo->select(Algorithm::Bubble);
}
Note that void(*)(std::vector<int>&) can point only to a namespace function or to static member. Pointers to members are class-specific and have to be called with special operator .* or ->*. What you may implement, is a CRTP with virtual base class (stripped of static vector and other bells and whistles for brevity):
#include <iostream>
#include <cstdlib>
class ActorBase
{
public:
// virtual interfaces
virtual void action() = 0;
};
template <class T>
class Actor : public ActorBase
{
protected:
typedef void(T::* FuncPtr)(/* params */);
FuncPtr algo;
public:
void action()
{
/* do call algo for appropriate object by treating this as pointer to T */
(dynamic_cast<T*>(this)->*algo)(/* args */);
}
};
class Concrete : public Actor<Concrete>
{
void bar() { std::cout << "Hello, Concrete!" << std::endl; }
public:
Concrete() { algo = &Concrete::bar; }
};
int main()
{
Concrete a;
a.action();
return EXIT_SUCCESS;
}
Curiously Recurrent Template Actor is very special template which can cast pointer to self to derived class. Still, it can't know anything about Concrete, e.g. typedefs or members. If it required to pass some traits like that, Actor Should be derived from a template class specialized for concrete T, known as trait class.
Not sure that this perverted approach is what actually needed to solve your X problem though, but at least it's syntactically correct. Here is a canonical CRTP.
Note that the call by member pointer requires .* \ -> AND parenthesis, because call operator () got higher priority than .*.

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
...

C++: Extend member type in derived class

I'd welcome some help with C++ inheritance to get a better grasp of the concept.
Is it possible to "extend" member types when creating a derived class? I think my problem can be best demonstrated by a simple example, where I'd like to extend the class VehicleData with a new double variable:
class VehicleData {
int yearOfManufacture;
//Different routines, for example Serialize(), etc., warranting to create a class for just a bunch of variables
};
class BicycleData:VehicleData {
double frameHeight; //new property that only applies to bicycles
};
//Now I create the actual classes that use the types above
class Vehicle {
VehicleData data;
void PrintData(); //a function that works on basic vehicle data
};
class Bicycle:Vehicle {
BicycleData data; //should copy VehicleData when creating an instance of this class
};
The problem with this approach is that when I code the above and create a Bicycle instance, its BicycleData member hides the already existing VehicleData member.
Is there a way to extend the base class, i.e. simply add a new double variable (to store frame height in this example), and keep the already existing (year of manufacture) data?
As far as I can tell, there is no clean way to do exactly what you want with inheritance alone.
You could create a template out of your base class:
template <typename Data>
class BaseVehicle
{
Data data;
// etc.
};
class Vehicle : BaseVehicle<VehicleData>
{
// etc.
};
class Bicycle : BaseVehicle<BicycleData>
{
// etc.
};
Then the Vehicle and Bicycle classes would contain data field of VehicleData and BicycleData types respectively.
Since in your example Bicycle inherits from Vehicle privately (i.e. there is no support for using Bicycle polymorphically via pointer/reference to Vehicle), this would effectively be identical to what you want to achieve.
If you do want dynamic polymorphism, you should create a separate, preferably abstract, class, defining the interface for your vehicles, e.g.:
class VehicleInterface
{
public:
// Some pure virtual interface methods
virtual void moveTo(const Vector2 position) = 0;
virtual ~VehicleInterface() = default;
};
And then you can have your concrete vehicles inherit and implement this interface:
class Vehicle : BaseVehicle<VehicleData>, public VehicleInterface
{
public:
virtual void moveTo(const Vector2 position) override
{
// implementation for Vehicle
}
};
class Bicycle : BaseVehicle<BicycleData>, public VehicleInterface
{
public:
virtual void moveTo(const Vector2 position) override
{
// implementation for Bicycle
}
};
Then any function, which would like to work with vehicles polymorphically, can just accept a reference or a pointer to VehicleInterface:
void driveToWork(VehicleInterface* vehicle)
{
vehicle->moveTo(getWorkPosition());
// etc.
}
Short answer; Not in the way that you're aiming for, but you can achieve something similar.
Rather than have an instance declared as you have, if you make data a pointer. You can then have BicycleData inherit VehicleData and then just replace data with the new instance in the constructor of the Bicycle.
ie
class Vehicle {
void PrintData();
protected:
void replaceData(std::shared_ptr<VehicleData> d) {
data = d;
}
std::shared_ptr<VehicleData> getData() {
return data;
}
template<class T>
std::shared_ptr<T> getDataAs() {
return std::dynamic_pointer_cast<T>(data);
}
private:
std::shared_ptr<VehicleData> data;
};
class Bicycle:Vehicle {
Bicycle(){replaceData(std::make_shared<BicycleData>());}
std::shared_ptr<BicycleData> getData() {
return getDataAs<BicycleData>();
}
};

C++ Specify variable type a posteriori in derived class

I have two databases of different types of objects with some common functions so I thought to create a parent class with the definitions of the common functions. The idea is that these functions have to do the same operations even though the type of objects is different. A silly example:
class Database
{
public:
// retrieve size of the dataset
int Size() const {return list_.size();}
};
class DerivedDatabase : public Database
{
private:
// list of dataset objects
std::vector<Object1> list_;
};
class DerivedDatabase2: public Database
{
private:
// list of dataset objects
std::vector<Object2> list_;
};
One solution is to define the function as virtual Size() const =0 and then have the derived classes override it. However the idea is to have it already implemented for when I have to create new types of DataBases. Is there a way to specify a posteriori the variable type in the derived classes? The two derived databases are inherently different and they behave completely differently except for some functions, which are common. Thus they have to be separate objects
You may use CRTP to factorize code, something like:
template <typename T> class Database
{
// T should have a container named list_
public:
// retrieve size of the dataset
int Size() const { return AsDerived().list_.size(); }
private:
const T& AsDerived() const { return static_cast<const T&>(*this); }
T& AsDerived() { return static_cast<T&>(*this); }
};
And then
class DerivedDatabase : public Database<DerivedDatabase>
{
friend class Database<DerivedDatabase>;
private:
std::vector<Object1> list_;
};
class DerivedDatabase2 : public Database<DerivedDatabase2>
{
friend class Database<DerivedDatabase2>;
private:
std::vector<Object2> list_;
};
Note that DerivedDatabase and DerivedDatabase2 doesn't share a common base type here
Live example
Sure, that what templates are for:
class Database {
virtual int size() = 0;
public:
// retrieve size of the dataset
int Size() const {return size();}
}
template<typename T>
class DerivedDatabase: public Database {
std::vector<T> list_;
int size() const {return list_.size();}
}

C++: what is the best way to handle this multi-inheritance?

A page is basically a fixed size array of a type - but it provides other functionality which isn't important for this question. Specifically, each page has a recordOffset which implies that the record IDs for the page are sequential and begin at this index (a page can be viewed as a discreet arbitrary segment of a larger array)
class AbstractPage
{
protected:
unsigned int recordOffset;
public:
AbstractPage(unsigned int recordOffset);
virtual ~AbstractPage();
// a mixture of pure and non-pure virtual functions
virtual string toString() const;
virtual unsigned int getCount() const = 0;
virtual PageType pageType() const = 0;
};
class IntegerPage : public AbstractPage
{
public:
vector<int> data;
IntegerPage(const vector<int>& data);
virtual ~IntegerPage();
// our concrete implementation
virtual unsigned int getCount() const;
virtual PageType pageType() const;
};
class FloatPage : public AbstractPage
{
public:
vector<float> data;
FloatPage(const vector<float>& data);
virtual ~FloatPage();
// our concrete implementation
virtual unsigned int getCount() const;
virtual PageType pageType() const;
};
I don't want to use templates for this because these pages get used liked this;
LinkedList<AbstractPage> pages;
I will use the interface methods provided by AbstractPage to interact with the page in most cases. When I need to read/write the data directly I will know the type separately and use:
dynamic_cast<FloatPage>(abstractPage).data[0] = 12.34;
So far so good, but here is the dilemma; I need to extend every type to create an indexed version of the page:
class AbstractIndexedPage
{
public:
// this is instead of the recordOffset of AbstractPage
vector<unsigned int> recordIds;
};
class IndexedIntegerPage : public AbstractIndexedPage, public IntegerPage
{
};
Now I want to be able to do this:
AbstractIndexedPage sort(const AbstractPage& page)
{
// Sorting will swap around the data and therefore we need to keep track of the
// record IDs in an Indexed page.
// If the incoming concrete type is IntegerPage, the output will be
// IndexedIntegerPage
}
The problem is the returned object will not have the interface to AbstractPage:
AbstractIndexedPage sortedPage = sort(originalPage);
sortedPage.getCount(); // can't do this!
dynamic_cast<AbstractPage>(sortedPage).getCount() // can do this, but pretty messy
From what I've read multiple inheritance in all but select cases means your code is basically designed badly. In this case there is multiple inheritance from two non-interfaces, both of the classes will have a constructor (and virtual destructor) but will only ever directly deal with the instance variables they provide.
My options are:
AbstractIndexedPage extends AbstractPage and use virtual inheritance since there will now be two AbstractPage. But that will give me the complete interface. But isn't this a naughty hack?
Just duplicate data or recordIds instance variables in IndexedIntegerPage and IntegerPage to give the same functionality without the need for inheritance.
Design the architecture differently?
Thanks
You can use delegation to do this work. For example, at AbstractIndexedPage:
class AbstractIndexedPage
{
public:
// this is instead of the recordOffset of AbstractPage
vector<unsigned int> recordIds;
AbstractClass* getPage() { return page;};
private:
AbstractClass *page;
};
and do something like that:
AbstractIndexedPage sortedPage = sort(originalPage);
sortedPage.getPage()->getCount(); // can't do this!
of course, verifying all possible errors or exeptions.
P.S. Someone will tell you to use smart pointer and I will agree with them, but, for simplicity, I just use plain pointer either
I was going to post this in comments, but the code will look terrible. You might consider abstracting at a lower level: create an AnyType, and just one Page Type based on it:
union AnyType {
float f;
int i;
};
class AnyPage : public AbstractPage
{
public:
enum PageDataType {FloatPage, IntPage};
vector<AnyType> data;
AnyPage(const vector<int>& data); //creates an 'IntPage'
AnyPage(const vector<float>& data); //creates a 'FloatPage'
virtual ~AnyPage();
// our concrete implementation
virtual unsigned int getCount() const;
virtual PageType pageType() const;
private:
PageDataType myType;
};
Then you can create your linked lists of AnyPage, and as you said, you already know which kind of page you are dealing with when you want to access the data:
anyPage.data[0].f = 12.34;
Then, for the indexed variety, it is no longer multiple inheritance:
class AnyIndexedPage : public AnyPage
{
public:
// this is instead of the recordOffset of AnyPage
vector<unsigned int> recordIds;
};