Database interface using inheritance and templates - c++

I am trying to implement a simple database interface than can handle different types, including custom classes. I wanted to pick inheritance or templates but it seems that I used both with no good results.
Header file
enum class RECORD_TYPE
{
TYPE_LONG = 11,
TYPE_STRING = 12
//other types
};
// the reason I created this class is to use it as function member parent
class RecordType
{
public:
RecordType(RECORD_TYPE record_type) : record_type_(record_type) {}
RECORD_TYPE get_record_type()
{
return record_type_;
}
protected:
RECORD_TYPE record_type_;
};
template<class T>
class RecordType_t : public RecordType
{
public:
RecordType_t(T value, RecordType type) : RecordType(type), value_(value) {}
const T &get_value() const { return value_; }
protected:
T value_;
};
class RecordType_long : public RecordType_t<long>
{
public:
RecordType_long(long value) : RecordType_t(value, RECORD_TYPE::TYPE_LONG) {};
};
class RecordType_string : public RecordType_t<std::string>
{
public:
RecordType_string(std::string value) : RecordType_t(value, RECORD_TYPE::TYPE_STRING) {};
};
Usage
void add_record(const RecordType &record)
{
//here I need to know the type(string/long/custom) because the types have to be stored different
switch (record.get_record_type())
{
case RECORD_TYPE::TYPE_LONG:
//long x = record.get_value();
case RECORD_TYPE::TYPE_STRING:
//string x = record.get_value();
//then do something with these values
};
};
Database db;
RecordType_string str("test");
db.add_record(str);
RecordType_long lng(200);
db.add_record(lng)
My main problem (apart from the fact that I am pretty sure it's bad design) is that in the function add() I don't have access to get_value() member function so I can get the values of each type. Because, of course, in the parent class, if I create the get_value(), I won't know what type to return.
Can you suggest how to implement better this thing?
Thank you
P.S. I could dynamically cast from RecordType into RecordType_long/RecordType_string/etc but I read here that this is really really bad design.:)

The problem is that templates provide a polymorphic behavior which is orthogonal to the one provided by inheritance.
The former provides parametric polimorphism while the latter provides subtyping.
These two different types of polymorphism doesn't mix together in C++. Each template specialization is a different type which is orthogonal to the others specialization of the same template, which means that there is no is-a relationship between such types as you have with inheritance.
So your choices really depend on the design you intend to use. To let each kind of field save itself on the database for example you would need to let each instance manage its own serialization without the need of knowing which is who, for example:
class SerializableRecord
{
public:
virtual void save(Database& db) const;
}
class RecordType_long : private RecordType_t<long>, public SerializableRecord
{
public:
void save(Database& db) const override {
long value = get_value();
/* save it on database somehow */
}
}
In this way you can use polymorphism and templates together but for two different purposes, without the need of knowing which specific kind of record you are going to save, of course this also implies that you need to work with pointers or object slicing occurs.
Another solution would be to make Database::save templated and specialize for various types:
class Database {
public:
template<typename T> void save(const T& record);
}
template<> void Database::save<RecordType_t<long>>(const RecordType_t<long>& record) {
long value = record.get_value();
// ...
}
Actually you have many options, it really depends what you need to achieve and the complexity of the structure itself.

Related

Functionality of a pure virtual function with variable return type - workaround/design?

I'm working on a very, very simple data access layer (DAL) featuring two classes: DataTransferObject (DTO) and DataAccessObject (DAO). Both classes are abstract base classes and need to be inherited and modified for a specific use case.
class DataTransferObject {
protected:
//protected constructor to prevent initialization
};
class DataAccessObject {
public:
virtual bool save(DataTransferObject o) = 0;
virtual DataTransferObject* load(int id) = 0;
};
in case of a House class from the business logic layer, the implementation of the DAL classes would read something along these lines:
class Dto_House : public DataTransferObject {
public:
int stories;
string address; //...which are all members of the House class...
Dto_House(House h);
};
class Dao_House : public DataAccessObject {
public:
bool save(Dto_House h) { /*...implement database access, etc...*/ }
Dto_House* load(int id) {/*...implement database access, etc...*/ }
};
EDIT: Of course, the derived classes know about the structure of the House class and the data storage.
Simple, nice, okidoke.
Now I wanted to provide a method toObject() in the DTO class in order to quickly convert the Dto_House into a House object. I then read about the automatic return type deduction in C++14 and tried:
class DataTransferObject {
public:
virtual auto toObject() = 0;
};
But I had to discover: No automatic return type deduction for virtual functions. :(
What are your ideas about implementing a "virtual function with deduced return type" for this specific case? I want a general toObject() function in my DTO "interface".
The only thing that came to my mind was something like:
template <typename T>
class DataTransferObject {
virtual T toObject() = 0;
};
class Dto_House : public DataTransferObject<House> {
public:
int stories;
string address;
House toObject() {return House(stories, address);}
};
EDIT:
A possible use case would be:
House h(3, "231 This Street");
h.doHouseStuff();
//save it
Dto_House dtoSave(h);
Dao_House dao;
dao.save(dtoSave); //even shorter: dao.save(Dto_House(h));
//now load some other house
Dto_House dtoLoad = dao.load(id 2);
h = dtoLoad.toObject();
h.doOtherHouseStuff();
But the house does not know it can be saved and loaded.
Of course, the abstract DAO class may be derived to further refine it for the use with, e.g. Sqlite, XML files or whatever... I just presented the very basic concept.
How about setting an empty abstract class - practically, an interface, then have both of your types implement it and set this as the toObject returning reference type?
class Transferable
{
virtual ~Transferable() = 0;
}
And then:
class DataTransferObject {
public:
//Return a reference of the object.
virtual Transferable& toObject() = 0;
};
Dto_House : public DataTransferObject, Transferable { /*...*/ }
House : public DataTransferObject, Transferable { /*...*/ }
The example above is to get my point.
Even better, you can use the DataTransferObject for this cause as your returning reference type, and no other abstract class:
class DataTransferObject {
public:
virtual DataTransferObject& toObject() = 0;
};
Dto_House : public DataTransferObject { /*...*/ }
House : public DataTransferObject { /*...*/ }
Update: If you want to have the classes separated apart, separating any association between data and operations by convention, you could set the name of the base class on something that represents the data i.e.: Building, Construction etc, and then use it for the reference type in toObject.
You can also have the class manipulating those operations on the API of data manipulation.
In general, you can not have a virtual function returning different types in different subclasses, as this violates the whole concept of statically typed language: if you call DataTransferObject::toObject(), the compiler does not know what type it is going to return until runtime.
And this highlight the main problem of your design: why do you need a base class at all? How are you going to use it? Calling DataTransferObject::toObject(), even if you use some magic to get it work (or use a dynamically typed language), sounds like a bad idea since you can not be sure what the return type is. You will anyway need some casts, or some ifs, etc, to get it working — or you will be using only the functionality common for all such objects (House, Road, etc.) — but then you just need a common base class for all of them.
In fact, there is one exception to the same return type rule: if you return a pointer to a class, you can use the Covariant return type concept: a subclass may override a virtual function to return a subclass of the original return type. If all your "objects" have a common base class, you may use something along the lines of
struct DataTransferObject {
virtual BaseObject* toObject() = 0;
};
struct Dto_House : public DataTransferObject {
virtual House* toObject() { /*...*/ } // assumes that House subclasses BaseObject
};
However, this will still leave the same problem: if all you have in your code is DataTransferObject, even if you (but not the compiler) know it is a Dto_House, you will need some cast, which might be unreliable.
On the other hand, you template solution seems quite good except that you will not be able to explicitly call DataTransferObject::toObject() (unless you know the type of the object), but that's a bad idea as I have explained.
So, I suggest you think on how you are going to actually use the base classes (even write some sample code), and make your choice based on that.

oop - C++ - Proper way to implement type-specific behavior?

Let's say I have a parent class, Arbitrary, and two child classes, Foo and Bar. I'm trying to implement a function to insert any Arbitrary object into a database, however, since the child classes contain data specific to those classes, I need to perform slightly different operations depending on the type.
Coming into C++ from Java/C#, my first instinct was to have a function that takes the parent as the parameter use something like instanceof and some if statements to handle child-class-specific behavior.
Pseudocode:
void someClass(Arbitrary obj){
obj.doSomething(); //a member function from the parent class
//more operations based on parent class
if(obj instanceof Foo){
//do Foo specific stuff
}
if(obj instanceof Bar){
//do Bar specific stuff
}
}
However, after looking into how to implement this in C++, the general consensus seemed to be that this is poor design.
If you have to use instanceof, there is, in most cases, something wrong with your design. – mslot
I considered the possibility of overloading the function with each type, but that would seemingly lead to code duplication. And, I would still end up needing to handle the child-specific behavior in the parent class, so that wouldn't solve the problem anyway.
So, my question is, what's the better way of performing operations that where all parent and child classes should be accepted as input, but in which behavior is dictated by the object type?
First, you want to take your Arbitrary by pointer or reference, otherwise you will slice off the derived class. Next, sounds like a case of a virtual method.
void someClass(Arbitrary* obj) {
obj->insertIntoDB();
}
where:
class Arbitrary {
public:
virtual ~Arbitrary();
virtual void insertIntoDB() = 0;
};
So that the subclasses can provide specific overrides:
class Foo : public Arbitrary {
public:
void insertIntoDB() override
// ^^^ if C++11
{
// do Foo-specific insertion here
}
};
Now there might be some common functionality in this insertion between Foo and Bar... so you should put that as a protected method in Arbitrary. protected so that both Foo and Bar have access to it but someClass() doesn't.
In my opinion, if at any place you need to write
if( is_instance_of(Derived1) )
//do something
else if ( is_instance_of(Derived2) )
//do somthing else
...
then it's as sign of bad design. First and most straight forward issue is that of "Maintainence". You have to take care in case further derivation happens. However, sometimes it's necessary. for e.g if your all classes are part of some library. In other cases you should avoid this coding as far as possible.
Most often you can remove the need to check for specific instance by introducing some new classes in the hierarchy. For e.g :-
class BankAccount {};
class SavingAccount : public BankAccount { void creditInterest(); };
class CheckingAccount : public BankAccount { void creditInterest(): };
In this case, there seems to be a need for if/else statement to check for actual object as there is no corresponsing creditInterest() in BanAccount class. However, indroducing a new class could obviate the need for that checking.
class BankAccount {};
class InterestBearingAccount : public BankAccount { void creditInterest(): } {};
class SavingAccount : public InterestBearingAccount { void creditInterest(): };
class CheckingAccount : public InterestBearingAccount { void creditInterest(): };
The issue here is that this will arguably violate SOLID design principles, given that any extension in the number of mapped classes would require new branches in the if statement, otherwise the existing dispatch method will fail (it won't work with any subclass, just those it knows about).
What you are describing looks well suited to inheritance polymorphicism - each of Arbitrary (base), Foo and Bar can take on the concerns of its own fields.
There is likely to be some common database plumbing which can be DRY'd up the base method.
class Arbitrary { // Your base class
protected:
virtual void mapFields(DbCommand& dbCommand) {
// Map the base fields here
}
public:
void saveToDatabase() { // External caller invokes this on any subclass
openConnection();
DbCommand& command = createDbCommand();
mapFields(command); // Polymorphic call
executeDbTransaction(command);
}
}
class Foo : public Arbitrary {
protected: // Hide implementation external parties
virtual void mapFields(DbCommand& dbCommand) {
Arbitrary::mapFields();
// Map Foo specific fields here
}
}
class Bar : public Arbitrary {
protected:
virtual void mapFields(DbCommand& dbCommand) {
Arbitrary::mapFields();
// Map Bar specific fields here
}
}
If the base class, Arbitrary itself cannot exist in isolation, it should also be marked as abstract.
As StuartLC pointed out, the current design violates the SOLID principles. However, both his answer and Barry's answer has strong coupling with the database, which I do not like (should Arbitrary really need to know about the database?). I would suggest that you make some additional abstraction, and make the database operations independent of the the data types.
One possible implementation may be like:
class Arbitrary {
public:
virtual std::string serialize();
static Arbitrary* deserialize();
};
Your database-related would be like (please notice that the parameter form Arbitrary obj is wrong and can truncate the object):
void someMethod(const Arbitrary& obj)
{
// ...
db.insert(obj.serialize());
}
You can retrieve the string from the database later and deserialize into a suitable object.
So, my question is, what's the better way of performing operations
that where all parent and child classes should be accepted as input,
but in which behavior is dictated by the object type?
You can use Visitor pattern.
#include <iostream>
using namespace std;
class Arbitrary;
class Foo;
class Bar;
class ArbitraryVisitor
{
public:
virtual void visitParent(Arbitrary& m) {};
virtual void visitFoo(Foo& vm) {};
virtual void visitBar(Bar& vm) {};
};
class Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Parent specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitParent(*this);
}
};
class Foo: public Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Foo specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitFoo(*this);
}
};
class Bar: public Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Bar specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitBar(*this);
}
};
class SetArbitaryVisitor : public ArbitraryVisitor
{
void visitParent(Arbitrary& vm)
{
vm.DoSomething();
}
void visitFoo(Foo& vm)
{
vm.DoSomething();
}
void visitBar(Bar& vm)
{
vm.DoSomething();
}
};
int main()
{
Arbitrary *arb = new Foo();
SetArbitaryVisitor scv;
arb->accept(scv);
}

C++ polymorphic functions with differing return types

I am creating a property class which stores a unique key and an arbitrary value as strings (plus an optional comment string for use when writing to configuration files). Currently I'm using the method of creating a base property class which holds the raw strings, and then subclassing this into type-specific properties - eg. an IntProperty which implements a getValue() function that converts the string to an int - to avoid having to convert a property value manually from a string every time I want to read it. These subclasses use getPropertyType(), a virtual function defined in the base and overridden in each of the derived, to return an enum value to identify which type of property they hold, and the base class returns a "none" identifier.
(As a side note, I shied away from templates because I'm using Qt and its required interface macro doesn't support templated objects. If it's worth using templates I may ditch the idea of using interfaces.)
My intention was to allow for lists of multiple different types of properties (string, int, float...) by subclassing them from the base property class and allowing arrays of base property pointers. However, I run into the problem that it then becomes very awkward to extract the property as a specific type from one of the derived classes, since the pointer to the base class obviously does not know about the newly defined getValue functions in the derived classes. I am left with either the option of extracting the string from the base class and converting manually or by casting the base class pointer to the correct derived class pointer. The first option renders the subclassing useless by requiring that I do the conversion manually, and the second sounds like a nightmare to code since there'll be a large switch statement involved on the property identifier value each time I want to work out which pointer to cast to.
What would be the most intelligent way of going about this problem? I want to keep the retrieval of property values as simple as possible - ie. have as little boilerplate code as I can to go from getting a base class pointer from an array to holding a properly typed copy of the property's value. Would it be worth considering the problem the other way around - have multiple strongly-typed property classes which all support getting and setting their respective value using a string?
What about this? (Untested, but you should get the idea)
class BaseType {
public:
virtual void getValue(string &s) { s = ""; };
virtual void getValue(int &i) { i = 0; };
virtual void getValue(double &d) { d = 0.0; };
};
class IntType : public BaseType {
public:
virtual void getValue(string &s) { s = to_string(myvalue); };
virtual void getValue(int &i) { i = myvalue; };
virtual void getValue(double &d) { d = static_cast<double>(myvalue); };
private:
int myvalue;
};
class DblType : public BaseType {
public:
virtual void getValue(string &s) { s = to_string(myvalue); };
virtual void getValue(int &i) { i = static_cast<int>myvalue; };
virtual void getValue(double &d) { d = myvalue; };
private:
double myvalue;
};
class StrType : public BaseType {
public:
virtual void getValue(string &s) { s = myvalue; };
virtual void getValue(int &i) { i = stoi(myvalue); };
virtual void getValue(double &d) { d = stod(myvalue); };
private:
string myvalue;
};
Surely, since the receiving side needs to know what type it's getting, using a name that indicates what you get back, e.g.
int GetInt(const string& key);
string GetString(const string& key);
double GetDouble(const string& key);
etc. would be just as good as calling it Get(const string& key) - and since the C++ language doesn't allow you to ONLY differentiate on the return type, that wouldn't work.
Another alternative is of course to have a
template <typename T>
void Get(const string& key, T& value);
(May need to actually implement all the different variant's differently, so it may not really help much to use a template, but it's much easier for me to write in an answer as a template! ;) )

Invalid covariant return type

Here is some representative code that gets the error I'm experiencing:
class Data
{
};
class Table
{
virtual std::vector<Data*> getData() = 0;
virtual void putData(Data* dataItem) = 0;
virtual Data* getData(int index) = 0;
};
class DerivedData : Data
{
};
class DerivedTable : Table
{
std::vector<DerivedData*> getData() { return myData; } // invalid covariant return type
void putData(DerivedData *dataItem) { myData.push_back(dataItem); }
virtual DerivedData* getData(int index) { return myData[index]; } // invalid covariant return type
std::vector<DerivedData*> myData;
};
Firstly, I don't quite understand why it is that the override of putData is happy with the parameters being changed, but I can't change the return type for getData, although I appreciate this is something I can gain an understanding of from more reading.
Secondly, and my main question, how could this code be changed to make it work. My basic goal is to allow for multiple "table" like objects which will store and control data objects. While each data object will share some things in common, there will be some distinct differences which the table will control and work with. For example, one table might have data objects which have a name parameter, and so the table will provide a function which prints a list of all the names of the data it holds. This way I can have generic code which works with all of these table objects, and specialized code which operates only with one type of table.
Many things are wrong:
The two versions of putData are simply different, unrelated overloads. There is no such thing as a "contravariant argument type" for overriding virtual functions in C++ (and even if there were, it would go the other way round!!). Add the keyword override to the derived function to make your compiler produce an error.
Class templates don't work the way you think. If template <typename T> class Foo is a class template, then Foo<X> and Foo<Y> are totally different, unlrelated classes, no matter whether X and Y are related in any way.
As #Beta says, you might just have a simple std::vector<std::unique_ptr<Data>> as your main data structure. But anyway, if you really must have some hierarchy, here's a possible "solution":
#include <memory>
#include <vector>
struct Data { virtual ~Data() { } };
struct Table
{
virtual ~Table() { }
typedef std::unique_ptr<Data> data_ptr;
typedef std::vector<data_ptr> dataset_type;
virtual dataset_type & getData() = 0;
virtual void putData(data_ptr dp) = 0;
virtual Data & getData(std::size_t n) = 0;
};
class DerivedTable : public Table
{
dataset_type myData;
public:
virtual void putData(data_ptr p) override
{
myData.push_back(std::move(p));
}
Data & getData(std::size_t n) override
{
return *myData[n];
}
// ...
};
"invalid covariant return type for" actually caused by the fact that you try to change the return type of getData(). Though return type isn't part of function identifier it still subject for some restriction.
Any method that overrides some base class should behave similary. I.e. virtual method implementation will try to do upcast to Data to return a valid pointer for clients that calls getData() from perspective of Table* (not DerviedTable*). This may be compared to (Data*)myData[index] from context of DerviedTable::getData(int).
That's the exact palce where compiler gets its confusion from.
class DerivedData : Data
{
};
This declaration says that DervidedData inherits Data privately. I.e. any client of DerviedData doesn't "know" that it in fact it is a Data.
That also makes generation of code for DerviedData* getData() override impossible since upcast to Data is inaccessible from DeviedTable::getData(int).
To make that error go away you can either make inheritance visbile to public:
class DerivedData : public Data
{
};
Or make a friend
class DerivedData : Data
{
friend class DerivedTable;
};
Though this design still a subject for questions.

Best way for derived classes to carry different data types in C++

What is the most elegant way to provide an interface in C++ that accepts derived class types that carry with them different data type members that then need to be retrieved later. The example below illustrates this where the Container class provides methods to "post" an Item that will be some kind of derived variant of BaseItem. Later on I want to get the derived Item back and extract its value.
The main thing I want is for the Container interface (post and receive) to stay the same in the future while allowing different "Item" derived types to be defined and "passed" through it. Would template be better for this somehow; I'd rather not use RTTI. Maybe there is some simple, elegant answer to this, but right now I'm struggling to think of it.
class ItemBase {
// common methods
};
class ItemInt : public ItemBase
{
private:
int dat;
public:
int get() { return dat; }
};
class ItemDouble : public ItemBase
{
private:
double dat;
public:
double get() { return dat; }
};
class Container {
public:
void post(int postHandle, ItemBase *e);
ItemBase* receive(int handle); // Returns the associated Item
};
int main()
{
ItemInt *ii = new IntItem(5);
Container c;
c.post(1, ii);
ItemInt *jj = c.receive(1);
int val = jj->get(); // want the value 5 out of the IntItem
}
This is definitely a candidate for generic programming, rather than inheritance. Remember, generics (templates) are ideal when you want identical handling for different data types. Your ItemInt and ItemDouble classes violate OO design principles (the get() method returns different data types depending on what the actual subtype is). Generic programming is built for that. The only other answer would be a tagged data type, and I personally avoid those like the plague.
How about?
template<typename T>
class Item
{
private:
T dat;
public:
T get() { return dat; }
};
class Container {
public:
template<typename T>
void post(int postHandle, Item<T> *e);
template<typename T>
Item<T>* receive(int handle); // Returns the associated Item
};
int main()
{
Item<int> *ii = new Item<int>(5);
Container c;
c.post(1, ii);
Item<int> *jj = c.receive<int>(1);
int val = jj->get(); // want the value 5 out of the IntItem
}
Your Container class looks suspiciously like a std::map. It looks to me like your ItemBase class is just a different name for "Object", the universal base class, which I think is not much different from (or better than) void*. I would avoid trying to contain items of different type in a single container. If your design seems to call for doing so, I'd rethink your design.
A pure template approach doesn't work because you apparently want to have mixed types in your container. You could work with something like Boost's any although I think you need to restore the actual. What I think is called for in this case is a base class exposing the type-independent and virtual methods plus a templatized derived class to hold the actual items:
class Base {
public:
virtual ~Base() {}
virtual void post() = 0;
};
template <typename T>
class Item: public Base {
public:
Item(T const& value): value_(value) {}
void post() { std::cout << "posting " << this->value_ << "\n"; }
private:
T value_;
};
This approach avoids the need to write any derived Item class for another value type. To make creation of these beast easier you probably want to create a suitable creation function as well, e.g.
template <typename T>
std::unique_ptr<Base> make_item(T const& value) {
return std::unique_ptr<Base>(new Item<T>(value));
}
A std::unique_ptr<Base> is returned to make sure that the allocated object is released (if you don't use C++2011 you can used std::auto_ptr<T> instead). This type can easily be converted to other pointer types, e.g. to a std::shared_ptr<Base> which is a better suited to be put into a container.