Inheritance & Template parameters

Discussion in 'C++' started by Thomas Matthews, Sep 10, 2004.

  1. Hi,

    I would like to apply inheritance to a template parameter, but my design
    fails to compile: cannot initialize one template class with child
    child parameterized class. I'll explain...

    Given:
    #include <string>

    // Parent class
    class Name_Id
    {
    public:
    Name_Id(const string& new_name,
    int new_id = 0)
    : name(new_name), id(new_id)
    {}
    virtual size_t max_width(void) const = 0;
    // Other methods here...
    private:
    string name;
    int id;
    };

    // Child classes
    class Category
    : public Name_Id
    {
    public:
    Category(const string& new_name)
    : Name_Id(new_name)
    { };
    size_t max_width(void) const
    { return 32};
    };

    class Title
    : public Name_Id
    {
    public:
    Title(const string& new_name)
    : Name_Id(new_name)
    { };
    size_t max_width(void) const
    { return 128};
    };

    template <typename AnyType>
    struct Iterator_Functor
    {
    virtual void operator()(AnyType& a) = 0;
    }

    I have a Name_Id database table class which
    contains Name_Id records. This is a base class
    for other tables of this kind.
    class Name_Table
    {
    public:
    void for_each(Iterator_Functor<AnyType>& functor);
    }
    The for_each method applies the functor to each record
    in the table.

    I have a Category_Table class which represents
    a database table containing Category objects:
    class Singleton;

    class Category_Table
    : public Name_Table, public Singleton
    {
    public:
    static Category_Table& ref(); //The singleton method.
    };

    I want to pass an Iterator_Functor<Category> to the
    "for_each" method of the Category_Table:
    Iterator_Functor<Category> functor;
    Category_Table::ref().for_each(functor);

    The compiler is complaining that a
    Iterator_Functor<Category>
    cannot be substituted for a
    Iterator_Functor<Name_Id>
    even though Category is-a Name_Id.

    I know the compiler is correct, but is there any
    work-around for this?




    --
    Thomas Matthews

    C++ newsgroup welcome message:
    http://www.slack.net/~shiva/welcome.txt
    C++ Faq: http://www.parashift.com/c -faq-lite
    C Faq: http://www.eskimo.com/~scs/c-faq/top.html
    alt.comp.lang.learn.c-c++ faq:
    http://www.comeaucomputing.com/learn/faq/
    Other sites:
    http://www.josuttis.com -- C++ STL Library book
     
    Thomas Matthews, Sep 10, 2004
    #1
    1. Advertising

  2. Thomas Matthews wrote:
    > I would like to apply inheritance to a template parameter, but my design
    > fails to compile: cannot initialize one template class with child
    > child parameterized class. I'll explain...
    >
    > Given:
    > #include <string>
    >
    > // Parent class
    > class Name_Id
    > {
    > public:
    > Name_Id(const string& new_name,
    > int new_id = 0)
    > : name(new_name), id(new_id)
    > {}
    > virtual size_t max_width(void) const = 0;
    > // Other methods here...
    > private:
    > string name;
    > int id;
    > };
    >
    > // Child classes
    > class Category
    > : public Name_Id
    > {
    > public:
    > Category(const string& new_name)
    > : Name_Id(new_name)
    > { };
    > size_t max_width(void) const
    > { return 32};
    > };
    >
    > class Title
    > : public Name_Id
    > {
    > public:
    > Title(const string& new_name)
    > : Name_Id(new_name)
    > { };
    > size_t max_width(void) const
    > { return 128};
    > };
    >
    > template <typename AnyType>
    > struct Iterator_Functor
    > {
    > virtual void operator()(AnyType& a) = 0;
    > }
    >
    > I have a Name_Id database table class which
    > contains Name_Id records. This is a base class
    > for other tables of this kind.
    > class Name_Table
    > {
    > public:
    > void for_each(Iterator_Functor<AnyType>& functor);


    How is this going to compile? 'AnyType' is not defined here. Did
    you forget to specify that 'for_each' is a template or that the
    whole class (Name_Table) is in fact a template? Or is this the case
    of "copy-paste in haste" error, and it has to be

    public:
    void for_each(Iterator_Functor<Name_Table>&);

    ???

    > }
    > The for_each method applies the functor to each record
    > in the table.


    Uh... Whatever...

    >
    > I have a Category_Table class which represents
    > a database table containing Category objects:
    > class Singleton;
    >
    > class Category_Table
    > : public Name_Table, public Singleton


    Are you deriving from an incomplete type here?

    > {
    > public:
    > static Category_Table& ref(); //The singleton method.
    > };
    >
    > I want to pass an Iterator_Functor<Category> to the
    > "for_each" method of the Category_Table:
    > Iterator_Functor<Category> functor;
    > Category_Table::ref().for_each(functor);
    >
    > The compiler is complaining that a
    > Iterator_Functor<Category>
    > cannot be substituted for a
    > Iterator_Functor<Name_Id>
    > even though Category is-a Name_Id.
    >
    > I know the compiler is correct, but is there any
    > work-around for this?


    Why not declare your Category_Table::functor as

    Iterator_Functor<Name_Table> functor;

    ?? What's so bad if it's a functor of the base class and not
    the derived one?

    V
     
    Victor Bazarov, Sep 10, 2004
    #2
    1. Advertising

  3. Thomas Matthews

    David Hilsee Guest

    "Thomas Matthews" <> wrote in
    message news:Ofl0d.9618$...
    > Hi,
    >
    > I would like to apply inheritance to a template parameter, but my design
    > fails to compile: cannot initialize one template class with child
    > child parameterized class. I'll explain...
    >
    > Given:
    > #include <string>
    >
    > // Parent class
    > class Name_Id
    > {
    > public:
    > Name_Id(const string& new_name,
    > int new_id = 0)
    > : name(new_name), id(new_id)
    > {}
    > virtual size_t max_width(void) const = 0;
    > // Other methods here...
    > private:
    > string name;
    > int id;
    > };
    >
    > // Child classes
    > class Category
    > : public Name_Id
    > {
    > public:
    > Category(const string& new_name)
    > : Name_Id(new_name)
    > { };
    > size_t max_width(void) const
    > { return 32};
    > };
    >
    > class Title
    > : public Name_Id
    > {
    > public:
    > Title(const string& new_name)
    > : Name_Id(new_name)
    > { };
    > size_t max_width(void) const
    > { return 128};
    > };
    >
    > template <typename AnyType>
    > struct Iterator_Functor
    > {
    > virtual void operator()(AnyType& a) = 0;
    > }
    >
    > I have a Name_Id database table class which
    > contains Name_Id records. This is a base class
    > for other tables of this kind.
    > class Name_Table
    > {
    > public:
    > void for_each(Iterator_Functor<AnyType>& functor);
    > }
    > The for_each method applies the functor to each record
    > in the table.
    >
    > I have a Category_Table class which represents
    > a database table containing Category objects:
    > class Singleton;
    >
    > class Category_Table
    > : public Name_Table, public Singleton
    > {
    > public:
    > static Category_Table& ref(); //The singleton method.
    > };
    >
    > I want to pass an Iterator_Functor<Category> to the
    > "for_each" method of the Category_Table:
    > Iterator_Functor<Category> functor;
    > Category_Table::ref().for_each(functor);
    >
    > The compiler is complaining that a
    > Iterator_Functor<Category>
    > cannot be substituted for a
    > Iterator_Functor<Name_Id>
    > even though Category is-a Name_Id.
    >
    > I know the compiler is correct, but is there any
    > work-around for this?


    There are lots of options.

    a) Define a for_each for Category_Table that takes an
    Iterator_Functor<Category>.
    b) Make for_each a template, so it can be used with many different functors,
    not just those that derive from Iterator_Functor<Name_Id> (template <class
    Func> void for_each(Func f)). What is the point of Iterator_Functor,
    anyway?
    c) Remove the inheritance relationship from Category_Table and Name_Table.
    Instead, provide a class template for holding objects (template <class T>
    Table { /* ... */ }; Table<Category> tab;). The current relationship looks
    suspicious, but I'd have to see more of their implementation to know if it's
    truly questionable.

    --
    David Hilsee
     
    David Hilsee, Sep 10, 2004
    #3
  4. David Hilsee wrote:
    > "Thomas Matthews" <> wrote in
    > message news:Ofl0d.9618$...
    >
    >
    > There are lots of options.
    >
    > a) Define a for_each for Category_Table that takes an
    > Iterator_Functor<Category>.
    > b) Make for_each a template, so it can be used with many different functors,
    > not just those that derive from Iterator_Functor<Name_Id> (template <class
    > Func> void for_each(Func f)). What is the point of Iterator_Functor,
    > anyway?

    Iterator_Functor is similar to a Visitor pattern. It allows me to pass
    a record to a functor derived from Iterator_Functor.
    struct Category_Displayer
    : Iterator_Functor<Category>
    {
    void operator()(Category& cat)
    {
    cout << cat << endl;
    }
    }

    The functor is basically imposing an interface requirement.


    > c) Remove the inheritance relationship from Category_Table and Name_Table.
    > Instead, provide a class template for holding objects (template <class T>
    > Table { /* ... */ }; Table<Category> tab;). The current relationship looks
    > suspicious, but I'd have to see more of their implementation to know if it's
    > truly questionable.
    >


    I'm working with the Borland Database Engine (BDE) using the Paradox
    table format.

    Unfortunately, the BDE API does not treat the table as a container, but
    as a wrapper around Delphi functionality.

    I have many Name-ID tables that vary in the string length and theme.
    For example, I have Titles, Authors and Publishers as singleton tables.
    Each would be specialization of a Name-ID table.

    I would like to hide the inheritance from the user of the table. Thus
    the Titles table would be a collection of Title objects, not Name-ID
    objects. This would prevent a user from appending Author objects
    to a Title table (even though Author and Title are both descendants
    of Name-ID).


    --
    Thomas Matthews

    C++ newsgroup welcome message:
    http://www.slack.net/~shiva/welcome.txt
    C++ Faq: http://www.parashift.com/c -faq-lite
    C Faq: http://www.eskimo.com/~scs/c-faq/top.html
    alt.comp.lang.learn.c-c++ faq:
    http://www.comeaucomputing.com/learn/faq/
    Other sites:
    http://www.josuttis.com -- C++ STL Library book
     
    Thomas Matthews, Sep 10, 2004
    #4
    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. arch
    Replies:
    2
    Views:
    322
  2. ian
    Replies:
    5
    Views:
    569
  3. Sebastian Faust
    Replies:
    4
    Views:
    432
    Sebastian Faust
    Oct 18, 2003
  4. case2005
    Replies:
    3
    Views:
    1,859
    Nicolas Pavlidis
    Feb 13, 2005
  5. kito
    Replies:
    2
    Views:
    438
Loading...

Share This Page