Purely Virtual Functions With Varying Data Types

Discussion in 'C++' started by Volkan YAZICI, Mar 17, 2011.

  1. Hi,

    I'd like to implement a simple database, that is, a collection of
    tables, where the tables are just a vector of rows, and rows are just
    a vector of fields with varying data types. I use a vector<Field> to
    represent a row, and Field has children like IntField, StringField,
    etc. Field class would have a getData() method, which is obviously
    expected to be defined as a purely virtual function in Field. But the
    problem is, what would be the function footprint of such a purely
    virtual function? That is, for IntField, it will be "const int&
    getData() const"; for StringField, it will be "const string& getData()
    const", etc. Can anybody help me on this, please? How should I
    approach the problem? Do you recommend another solution? (BTW, Field
    is also expected to have relevant ctor and comparison methods as well.
    FYI.)

    OTOH, one can argue that, why not using sth like Field<int>(),
    Field<string>(), etc.? In such a case, I won't be able to define a
    vector of different data types. That is, to denote a row, I'll use
    vector<Field<int>>, and I'll only be able to store "int"s, no other
    data types will be permitted.


    Regards.
     
    Volkan YAZICI, Mar 17, 2011
    #1
    1. Advertising

  2. On 3/17/2011 3:41 PM, Volkan YAZICI wrote:
    > I'd like to implement a simple database, that is, a collection of
    > tables, where the tables are just a vector of rows, and rows are just
    > a vector of fields with varying data types.


    I am not sure that I'd do it that way. Nothing simple about trying to
    squeeze the model of a generic record with unknown number of fields of
    unknown types into a standard container. The standard containers aren't
    suited for that, IMO.

    > I use a vector<Field> to
    > represent a row, and Field has children like IntField, StringField,


    "Children"? You mean, derived classes?

    > etc. Field class would have a getData() method, which is obviously
    > expected to be defined as a purely virtual function in Field. But the
    > problem is, what would be the function footprint of such a purely
    > virtual function? That is, for IntField, it will be "const int&
    > getData() const"; for StringField, it will be "const string& getData()
    > const", etc. Can anybody help me on this, please? How should I
    > approach the problem? Do you recommend another solution? (BTW, Field
    > is also expected to have relevant ctor and comparison methods as well.
    > FYI.)
    >
    > OTOH, one can argue that, why not using sth like Field<int>(),
    > Field<string>(), etc.? In such a case, I won't be able to define a
    > vector of different data types. That is, to denote a row, I'll use
    > vector<Field<int>>, and I'll only be able to store "int"s, no other
    > data types will be permitted.


    AIUI, to solve this using a statically typed language like C++ one would
    define 'Field' to have methods to "interpret" it depending on its
    "type", something like

    String asString() const;
    int asInt() const;

    and so on. They can be virtual or they can be non-virtual and forward
    the actual call to some virtual function *after* checking the "runtime
    type" of the Field.

    You will likely rely heavily on casts in the implementation of those
    methods.

    Also, check your favorite search engine. This *undoubtedly* has been
    done and probably published before.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Mar 17, 2011
    #2
    1. Advertising

  3. On 17 mar, 20:41, Volkan YAZICI <> wrote:
    > I'd like to implement a simple database, that is, a collection of
    > tables, where the tables are just a vector of rows, and rows are just
    > a vector of fields with varying data types. I use a vector<Field> to
    > represent a row, and Field has children like IntField, StringField,
    > etc. Field class would have a getData() method, which is obviously
    > expected to be defined as a purely virtual function in Field. But the
    > problem is, what would be the function footprint of such a purely
    > virtual function? That is, for IntField, it will be "const int&
    > getData() const"; for StringField, it will be "const string& getData()
    > const", etc. Can anybody help me on this, please? How should I
    > approach the problem? Do you recommend another solution? (BTW, Field
    > is also expected to have relevant ctor and comparison methods as well.
    > FYI.)

    [snip]

    What you are trying to achieve is called a variant.
    Boost provides one but you can roll your own quite easily.

    Concerning the interface issue, popular choice are;
    Variant<int,std::string,Foo> v;
    int value;

    // template member access
    value = v.getData<int>();
    // pseudo cast
    value = variant_cast<int>(v),
    // named member function (for fixed set of types)
    value = getInt();

    There are also solutions with proxies for data binding but it is more
    exotic.

    --
    Michael
     
    Michael Doubez, Mar 18, 2011
    #3
  4. Volkan YAZICI

    Paul Guest

    "Volkan YAZICI" <> wrote in message
    news:...
    > Hi,
    >
    > I'd like to implement a simple database, that is, a collection of
    > tables, where the tables are just a vector of rows, and rows are just
    > a vector of fields with varying data types. I use a vector<Field> to
    > represent a row, and Field has children like IntField, StringField,
    > etc. Field class would have a getData() method, which is obviously
    > expected to be defined as a purely virtual function in Field. But the
    > problem is, what would be the function footprint of such a purely
    > virtual function? That is, for IntField, it will be "const int&
    > getData() const"; for StringField, it will be "const string& getData()
    > const", etc. Can anybody help me on this, please? How should I
    > approach the problem? Do you recommend another solution? (BTW, Field
    > is also expected to have relevant ctor and comparison methods as well.
    > FYI.)
    >
    > OTOH, one can argue that, why not using sth like Field<int>(),
    > Field<string>(), etc.? In such a case, I won't be able to define a
    > vector of different data types. That is, to denote a row, I'll use
    > vector<Field<int>>, and I'll only be able to store "int"s, no other
    > data types will be permitted.
    >
    >

    Yes variant types are quite easy to impliment here's how to do it:

    #include <iostream>
    #include <string>

    template<typename T1 ,typename T2>
    class ItemBase{
    public:
    virtual ~ItemBase(){}
    virtual operator T1(){return 0;}
    virtual operator T2() {return 0;}
    virtual ItemBase<T1,T2>& getData(){;return *this;}
    };

    template<typename T, typename T1, typename T2>
    class DataItem: public ItemBase<T1,T2>{
    T itsData;
    public:
    DataItem(const T& p):itsData(p){}
    operator T(){return itsData;}
    };

    template<typename T1, typename T2>
    class Field{
    ItemBase<T1,T2>* itsData;
    public:
    Field(): itsData(0){}
    ~Field(){delete itsData;}
    void setData(const T1& p){itsData = new DataItem<T1,T1,T2>(p);}
    void setData(const T2& p){itsData = new DataItem<T2,T1,T2>(p);}

    ItemBase<T1,T2>& getData(){return *itsData;}

    };

    int main(){

    Field<int, std::string> f1, f2;
    f1.setData("string");
    f2.setData(5);

    std::cout<< f2.getData();
    std::cout<< (std::string)f1.getData(); /*Needs explicit cast to call
    correct conversion operator*/
    std::strings str = f1.getData(); /*Correct conversion is called without
    explicit cast.*/

    }


    Note how you need to be carefull with conversion rules.
    You need to add copy constructors etc to make it container safe. I left
    alot out so that you can easily understand the code paths. Just add T3 , T4
    etc to templates to get more types.

    HTH.
     
    Paul, Mar 18, 2011
    #4
  5. Volkan YAZICI

    Paul Guest

    "Paul" <> wrote in message
    news:ppLgp.124240$2...
    >
    > "Volkan YAZICI" <> wrote in message
    > news:...
    >> Hi,
    >>
    >> I'd like to implement a simple database, that is, a collection of
    >> tables, where the tables are just a vector of rows, and rows are just
    >> a vector of fields with varying data types. I use a vector<Field> to
    >> represent a row, and Field has children like IntField, StringField,
    >> etc. Field class would have a getData() method, which is obviously
    >> expected to be defined as a purely virtual function in Field. But the
    >> problem is, what would be the function footprint of such a purely
    >> virtual function? That is, for IntField, it will be "const int&
    >> getData() const"; for StringField, it will be "const string& getData()
    >> const", etc. Can anybody help me on this, please? How should I
    >> approach the problem? Do you recommend another solution? (BTW, Field
    >> is also expected to have relevant ctor and comparison methods as well.
    >> FYI.)
    >>
    >> OTOH, one can argue that, why not using sth like Field<int>(),
    >> Field<string>(), etc.? In such a case, I won't be able to define a
    >> vector of different data types. That is, to denote a row, I'll use
    >> vector<Field<int>>, and I'll only be able to store "int"s, no other
    >> data types will be permitted.
    >>
    >>

    > Yes variant types are quite easy to impliment here's how to do it:
    >
    > #include <iostream>
    > #include <string>
    >
    > template<typename T1 ,typename T2>
    > class ItemBase{
    > public:
    > virtual ~ItemBase(){}
    > virtual operator T1(){return 0;}
    > virtual operator T2() {return 0;}


    Note I would like to make the above functions pure virtual because they are
    never supposed to be called, but can't seem to do it, perhaps if I spent
    more time on it.



    > virtual ItemBase<T1,T2>& getData(){;return *this;}
    > };
    >
    > template<typename T, typename T1, typename T2>
    > class DataItem: public ItemBase<T1,T2>{
    > T itsData;
    > public:
    > DataItem(const T& p):itsData(p){}
    > operator T(){return itsData;}
    > };
    >
    > template<typename T1, typename T2>
    > class Field{
    > ItemBase<T1,T2>* itsData;
    > public:
    > Field(): itsData(0){}
    > ~Field(){delete itsData;}
    > void setData(const T1& p){itsData = new DataItem<T1,T1,T2>(p);}
    > void setData(const T2& p){itsData = new DataItem<T2,T1,T2>(p);}
    >
    > ItemBase<T1,T2>& getData(){return *itsData;}
    >
    > };
    >
    > int main(){
    >
    > Field<int, std::string> f1, f2;
    > f1.setData("string");
    > f2.setData(5);
    >
    > std::cout<< f2.getData();
    > std::cout<< (std::string)f1.getData(); /*Needs explicit cast to call
    > correct conversion operator*/
    > std::strings str = f1.getData(); /*Correct conversion is called without
    > explicit cast.*/
    >
    > }
    >
    >
    > Note how you need to be carefull with conversion rules.
    > You need to add copy constructors etc to make it container safe. I left
    > alot out so that you can easily understand the code paths. Just add T3 ,
    > T4 etc to templates to get more types.
    >
    > HTH.
    >
    >
     
    Paul, Mar 18, 2011
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alan Silver
    Replies:
    9
    Views:
    934
    Alan Silver
    Jun 23, 2005
  2. Replies:
    0
    Views:
    389
  3. Replies:
    12
    Views:
    510
  4. John Goche
    Replies:
    10
    Views:
    797
    Marcus Kwok
    Dec 8, 2006
  5. Angus
    Replies:
    6
    Views:
    296
    manish
    Aug 21, 2009
Loading...

Share This Page