How to do "derived" type extensions?

Discussion in 'C++' started by Kira Yamato, Jan 8, 2008.

  1. Kira Yamato

    Kira Yamato Guest

    Suppose class B is a subtype of class A, i.e.,
    class B : public A
    {
    ...
    };
    Then, in C++, a pointer to type B can be treated as a pointer to type
    A. So, I can do the following:
    B *b;
    A *a = b;
    This morphism of types is what makes C++ so powerful.

    But now how do I do the following kind of morphism? Suppose I have functions
    void foo(const B &);
    and
    void bar(const A &);
    I like to be able to declare a function pointer
    void (*fp)(const B&);
    and make "polymorphic" assignments like
    p = foo; // this is ok in C++.
    p = bar; // semantically this make sense, but C++ syntax won't
    allow this!

    I know the last line of code is not valid C++ because the function
    signatures are required to be the same. However, on a semantic level,
    I should be allowed to substitute calls to foo with calls to bar. This
    is what I mean:
    B b;
    foo(b); // I can substitute the function foo in this line to
    bar(b); // the function bar in this line.
    So, at least on a semantic level I should be able to declare a
    "polymorphic" function pointer that can points to both foo and bar
    types.
    void (*fp)(const B&) = bar;
    fp(b); // here, b is passed as type A to fp since bar accepts
    type A argument.

    But I can't, because C++ doesn't work this way.

    Now, I know the mantra "When in Rome, do as Romans." So, if this is
    not a feature of C++, then I should rework a solution that is in C++.
    But I'm just curious if anyone has a "good hack" to simulate this type
    of polymorphism in C++?

    --

    -kira
    Kira Yamato, Jan 8, 2008
    #1
    1. Advertising

  2. Kira Yamato

    dizzy Guest

    Kira Yamato wrote:

    > Suppose class B is a subtype of class A, i.e.,
    > class B : public A
    > {
    > ...
    > };
    > Then, in C++, a pointer to type B can be treated as a pointer to type
    > A. So, I can do the following:
    > B *b;
    > A *a = b;
    > This morphism of types is what makes C++ so powerful.
    >
    > But now how do I do the following kind of morphism? Suppose I have
    > functions
    > void foo(const B &);
    > and
    > void bar(const A &);
    > I like to be able to declare a function pointer
    > void (*fp)(const B&);
    > and make "polymorphic" assignments like
    > p = foo; // this is ok in C++.
    > p = bar; // semantically this make sense, but C++ syntax won't
    > allow this!


    Yes.

    >
    > I know the last line of code is not valid C++ because the function
    > signatures are required to be the same. However, on a semantic level,
    > I should be allowed to substitute calls to foo with calls to bar. This
    > is what I mean:
    > B b;
    > foo(b); // I can substitute the function foo in this line to
    > bar(b); // the function bar in this line.
    > So, at least on a semantic level I should be able to declare a
    > "polymorphic" function pointer that can points to both foo and bar
    > types.
    > void (*fp)(const B&) = bar;
    > fp(b); // here, b is passed as type A to fp since bar accepts
    > type A argument.
    >
    > But I can't, because C++ doesn't work this way.


    Right. You are using pointer to functions which are low level and have
    limited semantics vs what you want. You should instead use something like
    boost::function<> where you specify the signature of the function as per
    valid call not to match identically with the called function (that is, as
    long as the called function returned argument is convertible to your
    specified returned type for boost::function and as long as the input
    arguments are convertible from your specified ones to the ones the function
    actually takes then it compiles).

    This is basically some template machinery (you store the original function
    pointer as a type independent of the type you are suposed to call but when
    calling the proper conversions happen).

    > Now, I know the mantra "When in Rome, do as Romans." So, if this is
    > not a feature of C++, then I should rework a solution that is in C++.
    > But I'm just curious if anyone has a "good hack" to simulate this type
    > of polymorphism in C++?


    No need for a hack, but a nice C++ compile time typesafe solution, something
    like boost::function. Here example of what you want:

    #include <iostream>
    #include <typeinfo>
    #include <boost/function.hpp>

    struct A {};
    struct B: A {};

    bool func(A const& arg)
    {
    std::cout << "called: " << typeid(arg).name() << std::endl;
    }

    int main()
    {
    boost::function<int (B const&)> f = func;
    f(B());
    }

    --
    Dizzy
    dizzy, Jan 8, 2008
    #2
    1. Advertising

  3. Kira Yamato

    LR Guest

    Kira Yamato wrote:
    > Suppose class B is a subtype of class A, i.e.,
    > class B : public A
    > {
    > ...
    > };


    >
    > But now how do I do the following kind of morphism? Suppose I have
    > functions
    > void foo(const B &);
    > and
    > void bar(const A &);
    > I like to be able to declare a function pointer
    > void (*fp)(const B&);
    > and make "polymorphic" assignments like
    > p = foo; // this is ok in C++.
    > p = bar; // semantically this make sense, but C++ syntax won't
    > allow this!



    Would it be acceptable to create a function,
    void bar(const B &);
    and call bar(const A &) from that function?

    LR
    LR, Jan 8, 2008
    #3
  4. Kira Yamato

    Salt_Peter Guest

    On Jan 8, 8:17 am, Kira Yamato <> wrote:
    > Suppose class B is a subtype of class A, i.e.,
    > class B : public A
    > {
    > ...
    > };
    > Then, in C++, a pointer to type B can be treated as a pointer to type
    > A. So, I can do the following:
    > B *b;
    > A *a = b;
    > This morphism of types is what makes C++ so powerful.


    What perhaps needs to be noted is that an instance of type B is_an
    instance of type A.
    Its not correct to say that a pointer to a B 'can be treated' as a
    ponter to an A.

    Now, ask yourself what makes polymorphism work?

    >
    > But now how do I do the following kind of morphism? Suppose I have functions
    > void foo(const B &);
    > and
    > void bar(const A &);
    > I like to be able to declare a function pointer
    > void (*fp)(const B&);
    > and make "polymorphic" assignments like
    > p = foo; // this is ok in C++.
    > p = bar; // semantically this make sense, but C++ syntax won't
    > allow this!


    Of course it doesn't. If it did we'ld all play russian roulette.

    >
    > I know the last line of code is not valid C++ because the function
    > signatures are required to be the same.
    > However, on a semantic level,
    > I should be allowed to substitute calls to foo with calls to bar. This
    > is what I mean:
    > B b;
    > foo(b); // I can substitute the function foo in this line to
    > bar(b); // the function bar in this line.


    Yes, absolutely, its not 'should' - you definitely can and do.

    > So, at least on a semantic level I should be able to declare a
    > "polymorphic" function pointer that can points to both foo and bar
    > types.
    > void (*fp)(const B&) = bar;
    > fp(b); // here, b is passed as type A to fp since bar accepts
    > type A argument.
    >
    > But I can't, because C++ doesn't work this way.


    Thankfully so. You are expecting a pointer to a function with a given
    signature to accept a function signature of another type. How do you
    expect a call for one signature to induce a call to anything viable?
    Are you seriously suggesting that a program should silently construct
    an instance of B in order to accept a reference to a base class? Thats
    ludicrous and insane.

    Basicly, the solution is to declare
    void (*fp)(const A&);
    the parameter of function at the pointer can be any_kind_of_A.

    #include <iostream>
    #include <typeinfo>

    class A
    {
    public:
    virtual ~A() { } // <---- polymorphism
    };

    class B : public A { };
    class C : public B { };

    void bar(const A& a)
    {
    std::cout << typeid(a).name() << std::endl;
    }

    void foo(const B& b)
    {
    std::cout << typeid(b).name() << std::endl;
    }

    int main()
    {
    void (*fp)(const A&);

    fp = &bar;
    A a;
    fp(a);
    B b;
    fp(b); // <- b is passed as a B, see output below
    C c;
    fp(c);

    void (*fp_b)(const B&);
    fp_b = &foo;
    fp_b(b);
    // fp_b(a); // error:
    // invalid initialization of reference
    // of type 'const B&' from expression
    // of type A
    }

    /*
    A
    B // <- whats this !
    C
    B
    */

    Read the error again. Do you understand the implications if the
    program was allowed to generate an instance of B silently?

    >
    > Now, I know the mantra "When in Rome, do as Romans." So, if this is
    > not a feature of C++, then I should rework a solution that is in C++.
    > But I'm just curious if anyone has a "good hack" to simulate this type
    > of polymorphism in C++?
    >


    Sorry, hacking is not programming.
    Salt_Peter, Jan 8, 2008
    #4
  5. Kira Yamato

    Kira Yamato Guest

    On 2008-01-08 09:37:11 -0500, Salt_Peter <> said:

    > On Jan 8, 8:17 am, Kira Yamato <> wrote:
    >> Suppose class B is a subtype of class A, i.e.,
    >> class B : public A
    >> {
    >> ...
    >> };
    >> Then, in C++, a pointer to type B can be treated as a pointer to type
    >> A. So, I can do the following:
    >> B *b;
    >> A *a = b;
    >> This morphism of types is what makes C++ so powerful.

    >
    > What perhaps needs to be noted is that an instance of type B is_an
    > instance of type A.
    > Its not correct to say that a pointer to a B 'can be treated' as a
    > ponter to an A.


    I never even define the term "can be treated". So, how can you say it
    is incorrect?

    > [...]
    >> But now how do I do the following kind of morphism? Suppose I have functions
    >> void foo(const B &);
    >> and
    >> void bar(const A &);
    >> I like to be able to declare a function pointer
    >> void (*fp)(const B&);
    >> and make "polymorphic" assignments like
    >> p = foo; // this is ok in C++.
    >> p = bar; // semantically this make sense, but C++ syntax won't
    >> allow this!

    >
    > Of course it doesn't. If it did we'ld all play russian roulette.


    Huh?

    >
    >>
    >> I know the last line of code is not valid C++ because the function
    >> signatures are required to be the same.
    >> However, on a semantic level,
    >> I should be allowed to substitute calls to foo with calls to bar. This
    >> is what I mean:
    >> B b;
    >> foo(b); // I can substitute the function foo in this line to
    >> bar(b); // the function bar in this line.

    >
    > Yes, absolutely, its not 'should' - you definitely can and do.
    >
    >> So, at least on a semantic level I should be able to declare a
    >> "polymorphic" function pointer that can points to both foo and bar
    >> types.
    >> void (*fp)(const B&) = bar;
    >> fp(b); // here, b is passed as type A to fp since bar accepts
    >> type A argument.
    >>
    >> But I can't, because C++ doesn't work this way.

    >
    > Thankfully so. You are expecting a pointer to a function with a given
    > signature to accept a function signature of another type. How do you
    > expect a call for one signature to induce a call to anything viable?


    But it is not just any arbitrary type. B is a subtype of A. This is
    important. It makes the calls compatible in the following sense (in my
    comment after the following paragraph).

    > Are you seriously suggesting that a program should silently construct
    > an instance of B in order to accept a reference to a base class?


    No. There is no need to construct an instance of B. Suppose we forced
    void (*fp)(const B &) = (void (*)(const B &)) bar;
    where I remind you that
    void bar(const A &);
    Then the call
    fp(B());
    is equivalent to
    bar(B());
    which is perfectly ok because B is a subtype of A.

    > Thats
    > ludicrous and insane.


    Maybe it's just because you didn't understand what I was trying to do.
    I'm saying this because your program below is not what I was trying to
    do.

    >
    > Basicly, the solution is to declare
    > void (*fp)(const A&);
    > the parameter of function at the pointer can be any_kind_of_A.
    >
    > #include <iostream>
    > #include <typeinfo>
    >
    > class A
    > {
    > public:
    > virtual ~A() { } // <---- polymorphism
    > };
    >
    > class B : public A { };
    > class C : public B { };
    >
    > void bar(const A& a)
    > {
    > std::cout << typeid(a).name() << std::endl;
    > }
    >
    > void foo(const B& b)
    > {
    > std::cout << typeid(b).name() << std::endl;
    > }
    >
    > int main()
    > {
    > void (*fp)(const A&);
    >
    > fp = &bar;
    > A a;
    > fp(a);
    > B b;
    > fp(b); // <- b is passed as a B, see output below
    > C c;
    > fp(c);
    >
    > void (*fp_b)(const B&);
    > fp_b = &foo;
    > fp_b(b);
    > // fp_b(a); // error:
    > // invalid initialization of reference
    > // of type 'const B&' from expression
    > // of type A
    > }
    >
    > /*
    > A
    > B // <- whats this !
    > C
    > B
    > */


    Your program is not what I'm trying to accomplish. Your polymorphism
    is just on the argument of the function. In fact, why did you even
    declare pointers to functions fp and fp_b at all? You could've just
    used bar and foo directly.

    What I was trying to do is to declare a single pointer to functions
    that do not have exact signature but are compatible in the sense I
    described above, which I will describe to you again:

    If I declare a pointer which points to a function that expects type B,
    then it is semantically accepted to use in place of this pointer
    another function that actually expects only type A. This is because
    when you invoke through this function pointer, the argument of type B
    can be passed as an argument of type A. Here we assume B is a subtype
    of A.

    > [...]
    > Sorry, hacking is not programming.


    Just curious... What you define hacking as?

    --

    -kira
    Kira Yamato, Jan 8, 2008
    #5
  6. Kira Yamato

    Kira Yamato Guest

    On 2008-01-08 08:44:33 -0500, dizzy <> said:

    > Kira Yamato wrote:
    >
    >> Suppose class B is a subtype of class A, i.e.,
    >> class B : public A
    >> {
    >> ...
    >> };
    >> Then, in C++, a pointer to type B can be treated as a pointer to type
    >> A. So, I can do the following:
    >> B *b;
    >> A *a = b;
    >> This morphism of types is what makes C++ so powerful.
    >>
    >> But now how do I do the following kind of morphism? Suppose I have
    >> functions
    >> void foo(const B &);
    >> and
    >> void bar(const A &);
    >> I like to be able to declare a function pointer
    >> void (*fp)(const B&);
    >> and make "polymorphic" assignments like
    >> p = foo; // this is ok in C++.
    >> p = bar; // semantically this make sense, but C++ syntax won't
    >> allow this!

    >
    > Yes.
    >
    >>
    >> I know the last line of code is not valid C++ because the function
    >> signatures are required to be the same. However, on a semantic level,
    >> I should be allowed to substitute calls to foo with calls to bar. This
    >> is what I mean:
    >> B b;
    >> foo(b); // I can substitute the function foo in this line to
    >> bar(b); // the function bar in this line.
    >> So, at least on a semantic level I should be able to declare a
    >> "polymorphic" function pointer that can points to both foo and bar
    >> types.
    >> void (*fp)(const B&) = bar;
    >> fp(b); // here, b is passed as type A to fp since bar accepts
    >> type A argument.
    >>
    >> But I can't, because C++ doesn't work this way.

    >
    > Right. You are using pointer to functions which are low level and have
    > limited semantics vs what you want. You should instead use something like
    > boost::function<> where you specify the signature of the function as per
    > valid call not to match identically with the called function (that is, as
    > long as the called function returned argument is convertible to your
    > specified returned type for boost::function and as long as the input
    > arguments are convertible from your specified ones to the ones the function
    > actually takes then it compiles).
    >
    > This is basically some template machinery (you store the original function
    > pointer as a type independent of the type you are suposed to call but when
    > calling the proper conversions happen).
    >
    >> Now, I know the mantra "When in Rome, do as Romans." So, if this is
    >> not a feature of C++, then I should rework a solution that is in C++.
    >> But I'm just curious if anyone has a "good hack" to simulate this type
    >> of polymorphism in C++?

    >
    > No need for a hack, but a nice C++ compile time typesafe solution, something
    > like boost::function. Here example of what you want:
    >
    > #include <iostream>
    > #include <typeinfo>
    > #include <boost/function.hpp>
    >
    > struct A {};
    > struct B: A {};
    >
    > bool func(A const& arg)
    > {
    > std::cout << "called: " << typeid(arg).name() << std::endl;
    > }
    >
    > int main()
    > {
    > boost::function<int (B const&)> f = func;
    > f(B());
    > }


    This is neat! I didn't look deeper into it yet; but assuming this does
    indeed do compile-time type-checking, then this is some cool stuff.

    Can't wait to dig into boost to see how it's done.

    Thanks.

    --

    -kira
    Kira Yamato, Jan 8, 2008
    #6
  7. Kira Yamato

    Kira Yamato Guest

    On 2008-01-08 09:18:53 -0500, LR <> said:

    > Kira Yamato wrote:
    >> Suppose class B is a subtype of class A, i.e.,
    >> class B : public A
    >> {
    >> ...
    >> };

    >
    >>
    >> But now how do I do the following kind of morphism? Suppose I have functions
    >> void foo(const B &);
    >> and
    >> void bar(const A &);
    >> I like to be able to declare a function pointer
    >> void (*fp)(const B&);
    >> and make "polymorphic" assignments like
    >> p = foo; // this is ok in C++.
    >> p = bar; // semantically this make sense, but C++ syntax won't
    >> allow this!

    >
    >
    > Would it be acceptable to create a function,
    > void bar(const B &);


    You mean
    void foo(const B &);

    > and call bar(const A &) from that function?


    Why not?

    void foo(const B &b)
    {
    void bar(const A &);
    bar(b);
    }

    --

    -kira
    Kira Yamato, Jan 8, 2008
    #7
  8. Kira Yamato

    Salt_Peter Guest

    On Jan 8, 10:11 am, Kira Yamato <> wrote:
    > On 2008-01-08 09:18:53 -0500, LR <> said:
    >
    >
    >
    > > Kira Yamato wrote:
    > >> Suppose class B is a subtype of class A, i.e.,
    > >> class B : public A
    > >> {
    > >> ...
    > >> };

    >
    > >> But now how do I do the following kind of morphism? Suppose I have functions
    > >> void foo(const B &);
    > >> and
    > >> void bar(const A &);
    > >> I like to be able to declare a function pointer
    > >> void (*fp)(const B&);
    > >> and make "polymorphic" assignments like
    > >> p = foo; // this is ok in C++.
    > >> p = bar; // semantically this make sense, but C++ syntax won't
    > >> allow this!

    >
    > > Would it be acceptable to create a function,
    > > void bar(const B &);

    >
    > You mean
    > void foo(const B &);


    he's referring to the signature.

    >
    > > and call bar(const A &) from that function?

    >
    > Why not?
    >
    > void foo(const B &b)
    > {
    > void bar(const A &);
    > bar(b);
    >
    > }
    >
    > --
    >
    > -kira


    because you'ld call foo(const A& a) instead. or better:

    #include <iostream>
    #include <typeinfo>

    class A { public: virtual ~A() {} };
    class B : public A { };

    template< typename T >
    void func(const T& t )
    {
    std::cout << typeid(t).name() << std::endl;
    }

    int main()
    {
    A a;
    func(a);
    B b;
    func(b);

    void (*fp)(const A&);
    fp = &func<A>;
    fp(a);
    fp(b);
    }
    Salt_Peter, Jan 8, 2008
    #8
  9. Kira Yamato

    Salt_Peter Guest

    On Jan 8, 10:07 am, Kira Yamato <> wrote:
    > On 2008-01-08 09:37:11 -0500, Salt_Peter <> said:
    >
    >
    >
    > > On Jan 8, 8:17 am, Kira Yamato <> wrote:
    > >> Suppose class B is a subtype of class A, i.e.,
    > >> class B : public A
    > >> {
    > >> ...
    > >> };
    > >> Then, in C++, a pointer to type B can be treated as a pointer to type
    > >> A. So, I can do the following:
    > >> B *b;
    > >> A *a = b;
    > >> This morphism of types is what makes C++ so powerful.

    >
    > > What perhaps needs to be noted is that an instance of type B is_an
    > > instance of type A.
    > > Its not correct to say that a pointer to a B 'can be treated' as a
    > > ponter to an A.

    >
    > I never even define the term "can be treated". So, how can you say it
    > is incorrect?
    >
    > > [...]
    > >> But now how do I do the following kind of morphism? Suppose I have functions
    > >> void foo(const B &);
    > >> and
    > >> void bar(const A &);
    > >> I like to be able to declare a function pointer
    > >> void (*fp)(const B&);
    > >> and make "polymorphic" assignments like
    > >> p = foo; // this is ok in C++.
    > >> p = bar; // semantically this make sense, but C++ syntax won't
    > >> allow this!

    >
    > > Of course it doesn't. If it did we'ld all play russian roulette.

    >
    > Huh?
    >
    >
    >
    >
    >
    > >> I know the last line of code is not valid C++ because the function
    > >> signatures are required to be the same.
    > >> However, on a semantic level,
    > >> I should be allowed to substitute calls to foo with calls to bar. This
    > >> is what I mean:
    > >> B b;
    > >> foo(b); // I can substitute the function foo in this line to
    > >> bar(b); // the function bar in this line.

    >
    > > Yes, absolutely, its not 'should' - you definitely can and do.

    >
    > >> So, at least on a semantic level I should be able to declare a
    > >> "polymorphic" function pointer that can points to both foo and bar
    > >> types.
    > >> void (*fp)(const B&) = bar;
    > >> fp(b); // here, b is passed as type A to fp since bar accepts
    > >> type A argument.

    >
    > >> But I can't, because C++ doesn't work this way.

    >
    > > Thankfully so. You are expecting a pointer to a function with a given
    > > signature to accept a function signature of another type. How do you
    > > expect a call for one signature to induce a call to anything viable?

    >
    > But it is not just any arbitrary type. B is a subtype of A. This is
    > important. It makes the calls compatible in the following sense (in my
    > comment after the following paragraph).
    >
    > > Are you seriously suggesting that a program should silently construct
    > > an instance of B in order to accept a reference to a base class?

    >
    > No. There is no need to construct an instance of B. Suppose we forced
    > void (*fp)(const B &) = (void (*)(const B &)) bar;
    > where I remind you that
    > void bar(const A &);
    > Then the call
    > fp(B());
    > is equivalent to
    > bar(B());
    > which is perfectly ok because B is a subtype of A.
    >
    > > Thats
    > > ludicrous and insane.

    >
    > Maybe it's just because you didn't understand what I was trying to do.
    > I'm saying this because your program below is not what I was trying to
    > do.
    >
    >
    >
    >
    >
    > > Basicly, the solution is to declare
    > > void (*fp)(const A&);
    > > the parameter of function at the pointer can be any_kind_of_A.

    >
    > > #include <iostream>
    > > #include <typeinfo>

    >
    > > class A
    > > {
    > > public:
    > > virtual ~A() { } // <---- polymorphism
    > > };

    >
    > > class B : public A { };
    > > class C : public B { };

    >
    > > void bar(const A& a)
    > > {
    > > std::cout << typeid(a).name() << std::endl;
    > > }

    >
    > > void foo(const B& b)
    > > {
    > > std::cout << typeid(b).name() << std::endl;
    > > }

    >
    > > int main()
    > > {
    > > void (*fp)(const A&);

    >
    > > fp = &bar;
    > > A a;
    > > fp(a);
    > > B b;
    > > fp(b); // <- b is passed as a B, see output below
    > > C c;
    > > fp(c);

    >
    > > void (*fp_b)(const B&);
    > > fp_b = &foo;
    > > fp_b(b);
    > > // fp_b(a); // error:
    > > // invalid initialization of reference
    > > // of type 'const B&' from expression
    > > // of type A
    > > }

    >
    > > /*
    > > A
    > > B // <- whats this !
    > > C
    > > B
    > > */

    >
    > Your program is not what I'm trying to accomplish. Your polymorphism
    > is just on the argument of the function. In fact, why did you even
    > declare pointers to functions fp and fp_b at all? You could've just
    > used bar and foo directly.
    >
    > What I was trying to do is to declare a single pointer to functions
    > that do not have exact signature but are compatible in the sense I
    > described above, which I will describe to you again:
    >
    > If I declare a pointer which points to a function that expects type B,
    > then it is semantically accepted to use in place of this pointer
    > another function that actually expects only type A. This is because
    > when you invoke through this function pointer, the argument of type B
    > can be passed as an argument of type A. Here we assume B is a subtype
    > of A.
    >
    > > [...]
    > > Sorry, hacking is not programming.

    >
    > Just curious... What you define hacking as?
    >


    I'm sorry if i upset you, was not my intention. honest.
    Salt_Peter, Jan 8, 2008
    #9
  10. Kira Yamato

    Salt_Peter Guest

    On Jan 8, 10:07 am, Kira Yamato <> wrote:
    > On 2008-01-08 09:37:11 -0500, Salt_Peter <> said:
    >
    >
    >
    > > On Jan 8, 8:17 am, Kira Yamato <> wrote:
    > >> Suppose class B is a subtype of class A, i.e.,
    > >> class B : public A
    > >> {
    > >> ...
    > >> };
    > >> Then, in C++, a pointer to type B can be treated as a pointer to type
    > >> A. So, I can do the following:
    > >> B *b;
    > >> A *a = b;
    > >> This morphism of types is what makes C++ so powerful.

    >
    > > What perhaps needs to be noted is that an instance of type B is_an
    > > instance of type A.
    > > Its not correct to say that a pointer to a B 'can be treated' as a
    > > ponter to an A.

    >
    > I never even define the term "can be treated". So, how can you say it
    > is incorrect?
    >
    > > [...]
    > >> But now how do I do the following kind of morphism? Suppose I have functions
    > >> void foo(const B &);
    > >> and
    > >> void bar(const A &);
    > >> I like to be able to declare a function pointer
    > >> void (*fp)(const B&);
    > >> and make "polymorphic" assignments like
    > >> p = foo; // this is ok in C++.
    > >> p = bar; // semantically this make sense, but C++ syntax won't
    > >> allow this!

    >
    > > Of course it doesn't. If it did we'ld all play russian roulette.

    >
    > Huh?
    >
    >
    >
    >
    >
    > >> I know the last line of code is not valid C++ because the function
    > >> signatures are required to be the same.
    > >> However, on a semantic level,
    > >> I should be allowed to substitute calls to foo with calls to bar. This
    > >> is what I mean:
    > >> B b;
    > >> foo(b); // I can substitute the function foo in this line to
    > >> bar(b); // the function bar in this line.

    >
    > > Yes, absolutely, its not 'should' - you definitely can and do.

    >
    > >> So, at least on a semantic level I should be able to declare a
    > >> "polymorphic" function pointer that can points to both foo and bar
    > >> types.
    > >> void (*fp)(const B&) = bar;
    > >> fp(b); // here, b is passed as type A to fp since bar accepts
    > >> type A argument.

    >
    > >> But I can't, because C++ doesn't work this way.

    >
    > > Thankfully so. You are expecting a pointer to a function with a given
    > > signature to accept a function signature of another type. How do you
    > > expect a call for one signature to induce a call to anything viable?

    >
    > But it is not just any arbitrary type. B is a subtype of A. This is
    > important. It makes the calls compatible in the following sense (in my
    > comment after the following paragraph).
    >
    > > Are you seriously suggesting that a program should silently construct
    > > an instance of B in order to accept a reference to a base class?

    >
    > No. There is no need to construct an instance of B. Suppose we forced
    > void (*fp)(const B &) = (void (*)(const B &)) bar;
    > where I remind you that
    > void bar(const A &);
    > Then the call
    > fp(B());
    > is equivalent to
    > bar(B());
    > which is perfectly ok because B is a subtype of A.
    >
    > > Thats
    > > ludicrous and insane.

    >
    > Maybe it's just because you didn't understand what I was trying to do.
    > I'm saying this because your program below is not what I was trying to
    > do.
    >
    >
    >
    >
    >
    > > Basicly, the solution is to declare
    > > void (*fp)(const A&);
    > > the parameter of function at the pointer can be any_kind_of_A.

    >
    > > #include <iostream>
    > > #include <typeinfo>

    >
    > > class A
    > > {
    > > public:
    > > virtual ~A() { } // <---- polymorphism
    > > };

    >
    > > class B : public A { };
    > > class C : public B { };

    >
    > > void bar(const A& a)
    > > {
    > > std::cout << typeid(a).name() << std::endl;
    > > }

    >
    > > void foo(const B& b)
    > > {
    > > std::cout << typeid(b).name() << std::endl;
    > > }

    >
    > > int main()
    > > {
    > > void (*fp)(const A&);

    >
    > > fp = &bar;
    > > A a;
    > > fp(a);
    > > B b;
    > > fp(b); // <- b is passed as a B, see output below
    > > C c;
    > > fp(c);

    >
    > > void (*fp_b)(const B&);
    > > fp_b = &foo;
    > > fp_b(b);
    > > // fp_b(a); // error:
    > > // invalid initialization of reference
    > > // of type 'const B&' from expression
    > > // of type A
    > > }

    >
    > > /*
    > > A
    > > B // <- whats this !
    > > C
    > > B
    > > */

    >
    > Your program is not what I'm trying to accomplish. Your polymorphism
    > is just on the argument of the function. In fact, why did you even
    > declare pointers to functions fp and fp_b at all? You could've just
    > used bar and foo directly.
    >
    > What I was trying to do is to declare a single pointer to functions
    > that do not have exact signature but are compatible in the sense I
    > described above, which I will describe to you again:
    >
    > If I declare a pointer which points to a function that expects type B,
    > then it is semantically accepted to use in place of this pointer
    > another function that actually expects only type A. This is because
    > when you invoke through this function pointer, the argument of type B
    > can be passed as an argument of type A. Here we assume B is a subtype
    > of A.
    >
    > > [...]
    > > Sorry, hacking is not programming.

    >
    > Just curious... What you define hacking as?
    >
    > --
    >
    > -kira



    Not meant to upset you. Honest.
    take a look at the following, perhaps you'll get my drift:

    #include <iostream>
    #include <typeinfo>

    class A
    {
    public:
    virtual ~A() {}
    virtual void foo() const { std::cout << "A::foo()\n"; }
    virtual void bar() const { std::cout << "A::bar()\n"; }
    };

    class B : public A
    {
    public:
    void foo() const { std::cout << "B::foo()\n"; }
    void bar() const { std::cout << "B::bar()\n"; }
    };

    template< typename T >
    void func(const T& t )
    {
    std::cout << typeid(t).name() << std::endl;
    t.foo();
    }

    int main()
    {
    A a;
    func(a);
    B b;
    func(b);

    void (*fp)(const A&);
    fp = &func<A>;
    fp(a);
    fp(b);
    }

    /*
    A
    A::foo()
    B
    B::foo()
    A
    A::foo()
    B
    B::foo()
    */
    Salt_Peter, Jan 8, 2008
    #10
  11. Kira Yamato

    LR Guest

    Kira Yamato wrote:
    > On 2008-01-08 09:18:53 -0500, LR <> said:
    >
    >> Kira Yamato wrote:
    >>> Suppose class B is a subtype of class A, i.e.,
    >>> class B : public A
    >>> {
    >>> ...
    >>> };

    >>
    >>>
    >>> But now how do I do the following kind of morphism? Suppose I have
    >>> functions
    >>> void foo(const B &);
    >>> and
    >>> void bar(const A &);
    >>> I like to be able to declare a function pointer
    >>> void (*fp)(const B&);
    >>> and make "polymorphic" assignments like
    >>> p = foo; // this is ok in C++.
    >>> p = bar; // semantically this make sense, but C++ syntax won't
    >>> allow this!

    >>
    >>
    >> Would it be acceptable to create a function,
    >> void bar(const B &);

    >
    > You mean
    > void foo(const B &);


    No, that's not what I meant. I don't think that I made myself clear, so
    I'll try again.

    Untested, and not complete...

    This is what I think you started with.
    class A {
    };
    class B : public A {
    };
    void foo(const B &) {
    }
    void bar(const A &) {
    }

    now I suggest adding this function
    void bar(const B &b) {
    ::bar( reinterpret_cast<const A&>(b) );
    }

    so you can
    void (*fp)(const B&);
    and
    B b;
    fp = bar; // will assign the address of void bar(const B &) to fp
    fp(b);
    fp = foo;
    fp(b);

    Or else I didn't understand your question.

    LR
    LR, Jan 8, 2008
    #11
  12. Kira Yamato

    Pete Becker Guest

    On 2008-01-08 12:17:35 -0500, LR <> said:

    > class A {
    > };
    > class B : public A {
    > };
    > void foo(const B &) {
    > }
    > void bar(const A &) {
    > }
    >
    > now I suggest adding this function
    > void bar(const B &b) {
    > ::bar( reinterpret_cast<const A&>(b) );
    > }
    >


    Use static_cast instead of reinterpret_cast here.

    --
    Pete
    Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
    Standard C++ Library Extensions: a Tutorial and Reference
    (www.petebecker.com/tr1book)
    Pete Becker, Jan 8, 2008
    #12
  13. Kira Yamato

    LR Guest

    Pete Becker wrote:
    > On 2008-01-08 12:17:35 -0500, LR <> said:
    >
    >> class A {
    >> };
    >> class B : public A {
    >> };
    >> void foo(const B &) {
    >> }
    >> void bar(const A &) {
    >> }
    >>
    >> now I suggest adding this function
    >> void bar(const B &b) {
    >> ::bar( reinterpret_cast<const A&>(b) );
    >> }
    >>

    >
    > Use static_cast instead of reinterpret_cast here.
    >


    I meant to type dynamic_cast. For the two compilers I've tried this
    kind of thing with I like the error messages better when I make other
    mistakes.

    But I agree that reininterpret_cast doesn't belong there. Thanks.

    LR
    LR, Jan 8, 2008
    #13
  14. Kira Yamato

    Pete Becker Guest

    On 2008-01-08 12:55:13 -0500, LR <> said:

    > Pete Becker wrote:
    >> On 2008-01-08 12:17:35 -0500, LR <> said:
    >>
    >>> class A {
    >>> };
    >>> class B : public A {
    >>> };
    >>> void foo(const B &) {
    >>> }
    >>> void bar(const A &) {
    >>> }
    >>>
    >>> now I suggest adding this function
    >>> void bar(const B &b) {
    >>> ::bar( reinterpret_cast<const A&>(b) );
    >>> }
    >>>

    >>
    >> Use static_cast instead of reinterpret_cast here.
    >>

    >
    > I meant to type dynamic_cast. For the two compilers I've tried this
    > kind of thing with I like the error messages better when I make other
    > mistakes.
    >


    Nevertheless, the correct cast is static_cast. This kind of conversion
    is exactly what it's intended for.

    --
    Pete
    Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
    Standard C++ Library Extensions: a Tutorial and Reference
    (www.petebecker.com/tr1book)
    Pete Becker, Jan 8, 2008
    #14
  15. Kira Yamato

    LR Guest

    Pete Becker wrote:
    > On 2008-01-08 12:55:13 -0500, LR <> said:
    >
    >> Pete Becker wrote:
    >>> On 2008-01-08 12:17:35 -0500, LR <> said:
    >>>
    >>>> class A {
    >>>> };
    >>>> class B : public A {
    >>>> };
    >>>> void foo(const B &) {
    >>>> }
    >>>> void bar(const A &) {
    >>>> }
    >>>>
    >>>> now I suggest adding this function
    >>>> void bar(const B &b) {
    >>>> ::bar( reinterpret_cast<const A&>(b) );
    >>>> }
    >>>>
    >>>
    >>> Use static_cast instead of reinterpret_cast here.
    >>>

    >>
    >> I meant to type dynamic_cast. For the two compilers I've tried this
    >> kind of thing with I like the error messages better when I make other
    >> mistakes.
    >>

    >
    > Nevertheless, the correct cast is static_cast. This kind of conversion
    > is exactly what it's intended for.


    Why in this case is static_cast better than dynamic_cast?

    LR
    LR, Jan 9, 2008
    #15
  16. Kira Yamato

    Kira Yamato Guest

    On 2008-01-08 11:18:23 -0500, Salt_Peter <> said:

    > On Jan 8, 10:11 am, Kira Yamato <> wrote:
    >> On 2008-01-08 09:18:53 -0500, LR <> said:
    >>
    >>
    >>
    >>> Kira Yamato wrote:
    >>>> Suppose class B is a subtype of class A, i.e.,
    >>>> class B : public A
    >>>> {
    >>>> ...
    >>>> };

    >>
    >>>> But now how do I do the following kind of morphism? Suppose I have functions
    >>>> void foo(const B &);
    >>>> and
    >>>> void bar(const A &);
    >>>> I like to be able to declare a function pointer
    >>>> void (*fp)(const B&);
    >>>> and make "polymorphic" assignments like
    >>>> p = foo; // this is ok in C++.
    >>>> p = bar; // semantically this make sense, but C++ syntax won't
    >>>> allow this!

    >>
    >>> Would it be acceptable to create a function,
    >>> void bar(const B &);

    >>
    >> You mean
    >> void foo(const B &);

    >
    > he's referring to the signature.
    >
    >>
    >>> and call bar(const A &) from that function?

    >>
    >> Why not?
    >>
    >> void foo(const B &b)
    >> {
    >> void bar(const A &);
    >> bar(b);
    >>
    >> }
    >>
    >> --
    >>
    >> -kira

    >
    > because you'ld call foo(const A& a) instead. or better:
    >
    > #include <iostream>
    > #include <typeinfo>
    >
    > class A { public: virtual ~A() {} };
    > class B : public A { };
    >
    > template< typename T >
    > void func(const T& t )
    > {
    > std::cout << typeid(t).name() << std::endl;
    > }
    >
    > int main()
    > {
    > A a;
    > func(a);
    > B b;
    > func(b);
    >
    > void (*fp)(const A&);
    > fp = &func<A>;
    > fp(a);
    > fp(b);
    > }


    But the following will not compile:
    fp = &func<B>;

    So, if I specialize for func<B>, your code won't work as is.

    However, there is probably a solution using templates and casts, as a
    few other posters have hinted.

    --

    -kira
    Kira Yamato, Jan 9, 2008
    #16
  17. Kira Yamato

    Kira Yamato Guest

    On 2008-01-08 12:17:35 -0500, LR <> said:

    > Kira Yamato wrote:
    >> On 2008-01-08 09:18:53 -0500, LR <> said:
    >>
    >>> Kira Yamato wrote:
    >>>> Suppose class B is a subtype of class A, i.e.,
    >>>> class B : public A
    >>>> {
    >>>> ...
    >>>> };
    >>>
    >>>>
    >>>> But now how do I do the following kind of morphism? Suppose I have functions
    >>>> void foo(const B &);
    >>>> and
    >>>> void bar(const A &);
    >>>> I like to be able to declare a function pointer
    >>>> void (*fp)(const B&);
    >>>> and make "polymorphic" assignments like
    >>>> p = foo; // this is ok in C++.
    >>>> p = bar; // semantically this make sense, but C++ syntax won't
    >>>> allow this!
    >>>
    >>>
    >>> Would it be acceptable to create a function,
    >>> void bar(const B &);

    >>
    >> You mean
    >> void foo(const B &);

    >
    > No, that's not what I meant. I don't think that I made myself clear,
    > so I'll try again.
    >
    > Untested, and not complete...
    >
    > This is what I think you started with.
    > class A {
    > };
    > class B : public A {
    > };
    > void foo(const B &) {
    > }
    > void bar(const A &) {
    > }
    >
    > now I suggest adding this function
    > void bar(const B &b) {
    > ::bar( reinterpret_cast<const A&>(b) );
    > }
    >
    > so you can
    > void (*fp)(const B&);
    > and
    > B b;
    > fp = bar; // will assign the address of void bar(const B &) to fp
    > fp(b);
    > fp = foo;
    > fp(b);


    Yes. This is a nice work-around in the sense that it is direct and
    seemingly not too much artifact.

    Your solution is similar to the adaptor pattern (or am I misusing the
    terminology here?).

    Thanks for the suggestion.

    --

    -kira
    Kira Yamato, Jan 9, 2008
    #17
  18. Kira Yamato

    LR Guest

    Kira Yamato wrote:
    > On 2008-01-08 12:17:35 -0500, LR <> said:
    >
    >> Kira Yamato wrote:
    >>> On 2008-01-08 09:18:53 -0500, LR <> said:
    >>>
    >>>> Kira Yamato wrote:
    >>>>> Suppose class B is a subtype of class A, i.e.,
    >>>>> class B : public A
    >>>>> {
    >>>>> ...
    >>>>> };
    >>>>
    >>>>>
    >>>>> But now how do I do the following kind of morphism? Suppose I have
    >>>>> functions
    >>>>> void foo(const B &);
    >>>>> and
    >>>>> void bar(const A &);
    >>>>> I like to be able to declare a function pointer
    >>>>> void (*fp)(const B&);
    >>>>> and make "polymorphic" assignments like
    >>>>> p = foo; // this is ok in C++.
    >>>>> p = bar; // semantically this make sense, but C++ syntax
    >>>>> won't allow this!
    >>>>
    >>>>
    >>>> Would it be acceptable to create a function,
    >>>> void bar(const B &);
    >>>
    >>> You mean
    >>> void foo(const B &);

    >>
    >> No, that's not what I meant. I don't think that I made myself clear,
    >> so I'll try again.
    >>
    >> Untested, and not complete...
    >>
    >> This is what I think you started with.
    >> class A {
    >> };
    >> class B : public A {
    >> };
    >> void foo(const B &) {
    >> }
    >> void bar(const A &) {
    >> }
    >>
    >> now I suggest adding this function
    >> void bar(const B &b) {
    >> ::bar( reinterpret_cast<const A&>(b) );
    >> }
    >>
    >> so you can
    >> void (*fp)(const B&);
    >> and
    >> B b;
    >> fp = bar; // will assign the address of void bar(const B &) to fp
    >> fp(b);
    >> fp = foo;
    >> fp(b);

    >
    > Yes. This is a nice work-around in the sense that it is direct and
    > seemingly not too much artifact.
    >
    > Your solution is similar to the adaptor pattern (or am I misusing the
    > terminology here?).


    I suppose in some ways, maybe not in others. However, consider this
    well known, although I don't know the source, quote: "any [programming]
    problem can be solved by introducing an extra level of indirection."


    > Thanks for the suggestion.



    You're welcome.

    Please don't overlook Pete Becker's correction and advice to use
    static_cast instead of reinterpret_cast elsethread.

    BTW, I've been thinking about this, and wondering about what you want to
    do because I suspect this might be a little bit of a maintenance problem
    if you're using this extensively in your code and your class structure
    changes.

    LR
    LR, Jan 9, 2008
    #18
  19. Kira Yamato

    Kira Yamato Guest

    On 2008-01-09 13:46:24 -0500, LR <> said:

    > Kira Yamato wrote:
    >> On 2008-01-08 12:17:35 -0500, LR <> said:
    >>
    >>> Kira Yamato wrote:
    >>>> On 2008-01-08 09:18:53 -0500, LR <> said:
    >>>>
    >>>>> Kira Yamato wrote:
    >>>>>> Suppose class B is a subtype of class A, i.e.,
    >>>>>> class B : public A
    >>>>>> {
    >>>>>> ...
    >>>>>> };
    >>>>>
    >>>>>>
    >>>>>> But now how do I do the following kind of morphism? Suppose I have functions
    >>>>>> void foo(const B &);
    >>>>>> and
    >>>>>> void bar(const A &);
    >>>>>> I like to be able to declare a function pointer
    >>>>>> void (*fp)(const B&);
    >>>>>> and make "polymorphic" assignments like
    >>>>>> p = foo; // this is ok in C++.
    >>>>>> p = bar; // semantically this make sense, but C++ syntax won't
    >>>>>> allow this!
    >>>>>
    >>>>>
    >>>>> Would it be acceptable to create a function,
    >>>>> void bar(const B &);
    >>>>
    >>>> You mean
    >>>> void foo(const B &);
    >>>
    >>> No, that's not what I meant. I don't think that I made myself clear,
    >>> so I'll try again.
    >>>
    >>> Untested, and not complete...
    >>>
    >>> This is what I think you started with.
    >>> class A {
    >>> };
    >>> class B : public A {
    >>> };
    >>> void foo(const B &) {
    >>> }
    >>> void bar(const A &) {
    >>> }
    >>>
    >>> now I suggest adding this function
    >>> void bar(const B &b) {
    >>> ::bar( reinterpret_cast<const A&>(b) );
    >>> }
    >>>
    >>> so you can
    >>> void (*fp)(const B&);
    >>> and
    >>> B b;
    >>> fp = bar; // will assign the address of void bar(const B &) to fp
    >>> fp(b);
    >>> fp = foo;
    >>> fp(b);

    >>
    >> Yes. This is a nice work-around in the sense that it is direct and
    >> seemingly not too much artifact.
    >>
    >> Your solution is similar to the adaptor pattern (or am I misusing the
    >> terminology here?).

    >
    > I suppose in some ways, maybe not in others. However, consider this
    > well known, although I don't know the source, quote: "any [programming]
    > problem can be solved by introducing an extra level of indirection."
    >
    >
    >> Thanks for the suggestion.

    >
    >
    > You're welcome.
    >
    > Please don't overlook Pete Becker's correction and advice to use
    > static_cast instead of reinterpret_cast elsethread.


    Yes. I've read that.

    >
    > BTW, I've been thinking about this, and wondering about what you want
    > to do because I suspect this might be a little bit of a maintenance
    > problem if you're using this extensively in your code and your class
    > structure changes.


    It started as a purely academic question. Since I notice the power of
    C++ comes from the abstraction that allows writing codes which operates
    on compatible types, I wonder if this concept could extend to "derived"
    types too.

    By "derived" types, I mean types that depend on object types, e.g.,
    functions with parameters of polymorphic types, or templates that
    depend on object types. How would you declare pointers to those things?

    We can even go further with this idea, like types that depend on these
    derived types. For example, a function whose parameter is a template
    of object types.

    --

    -kira
    Kira Yamato, Jan 10, 2008
    #19
    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. Vijai Kalyan
    Replies:
    4
    Views:
    301
    Jim Langston
    Sep 7, 2005
  2. Replies:
    4
    Views:
    405
    Alf P. Steinbach
    May 23, 2007
  3. Replies:
    1
    Views:
    393
    myork
    May 23, 2007
  4. Replies:
    1
    Views:
    385
    Victor Bazarov
    May 23, 2007
  5. David
    Replies:
    3
    Views:
    401
    Grizlyk
    Jan 29, 2008
Loading...

Share This Page