Cast to derived class?

Discussion in 'C++' started by christian.pontesegger@googlemail.com, Nov 12, 2007.

  1. Guest

    Hi all,

    lately I had a problem where I wanted to cast a basic class to a
    derived type, which did not introduce any new members and did not
    change any stuff with dynamically allocated memory. I just wanted to
    add some methods to the class.

    So my question is:
    Is it valid C++ to create a basic class and to cast it to a derived
    one the way I did in my example below? The example works fine for
    MinGW, but I'm not sure if this is ABI dependent.

    Example code:

    <code>

    #include <stdio.h>

    class Basic {

    public:
    Basic(int a, int b) {
    a_ = a;
    b_ = b;
    };

    int getA() {
    return a_;
    };
    int getB() {
    return b_;
    };

    private:
    int a_, b_;
    };

    class Derived : Basic {

    public:
    Derived(int a, int b) : Basic(a, b) {}
    ;

    int multiply() {
    return getA() * getB();
    };
    };


    int main() {
    Basic *basic = new Basic(2, 4);

    Derived *derived = (Derived *)basic;
    printf("%d * %d = %d\n", basic->getA(), basic->getB(), derived-
    >multiply());


    delete basic;

    return 0;
    }

    </code>
    , Nov 12, 2007
    #1
    1. Advertising

  2. * :
    > Hi all,
    >
    > lately I had a problem where I wanted to cast a basic class to a
    > derived type, which did not introduce any new members and did not
    > change any stuff with dynamically allocated memory. I just wanted to
    > add some methods to the class.
    >
    > So my question is:
    > Is it valid C++ to create a basic class and to cast it to a derived
    > one the way I did in my example below?


    No, it's Undefined Behavior.


    > Example code:
    >
    > <code>
    >
    > #include <stdio.h>
    >
    > class Basic {
    >
    > public:
    > Basic(int a, int b) {
    > a_ = a;
    > b_ = b;
    > };
    >
    > int getA() {
    > return a_;
    > };


    The prefix "get" serves no useful purpose. It just clutters the code
    and incorrectly indicates some dynamic action to obtain the value.


    > int getB() {
    > return b_;
    > };
    >
    > private:
    > int a_, b_;
    > };
    >
    > class Derived : Basic {
    >
    > public:
    > Derived(int a, int b) : Basic(a, b) {}
    > ;
    >
    > int multiply() {
    > return getA() * getB();
    > };
    > };
    >
    >
    > int main() {
    > Basic *basic = new Basic(2, 4);
    >
    > Derived *derived = (Derived *)basic;
    > printf("%d * %d = %d\n", basic->getA(), basic->getB(), derived-
    >> multiply());

    >
    > delete basic;
    >
    > return 0;
    > }
    >
    > </code>


    All you're achieving is the member function notation, and that's far too
    little to justify using implementation specific behavior.

    Instead, in this particular case, define

    int productOver( Base const& x ) { return x.a()*x.b(); }

    Cheers, & hth.,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Nov 12, 2007
    #2
    1. Advertising

  3. Alf P. Steinbach wrote:
    >> int getA() {
    >> return a_;
    >> };

    >
    > The prefix "get" serves no useful purpose. It just clutters the code
    > and incorrectly indicates some dynamic action to obtain the value.


    What kind of strange principle is that?

    So what if it "incorrectly indicates some dynamic action"? It's a
    public interface. You *don't know* what it does inside. You *don't care*
    what it does inside. It could perform an SQL database search for all you
    know. The only thing you care is what it's defined to do, ie. it returns
    a specified value, and that's it.

    "get<something>()" is a perfectly valid and good member function name.
    It's descriptive and concise, and above all, it's abstract. It hides the
    actual implementation, which is good.

    If it was somehow named after what it actually does (eg. simply
    returns a member variable), then what happens if in the future its
    implementation is changed to something else? Are you going to change the
    name of the function to reflect that?
    Juha Nieminen, Nov 12, 2007
    #3
  4. * Juha Nieminen:
    > Alf P. Steinbach wrote:
    >>> int getA() {
    >>> return a_;
    >>> };

    >> The prefix "get" serves no useful purpose. It just clutters the code
    >> and incorrectly indicates some dynamic action to obtain the value.

    >
    > What kind of strange principle is that?
    >
    > So what if it "incorrectly indicates some dynamic action"? It's a
    > public interface. You *don't know* what it does inside. You *don't care*
    > what it does inside. It could perform an SQL database search for all you
    > know. The only thing you care is what it's defined to do, ie. it returns
    > a specified value, and that's it.
    >
    > "get<something>()" is a perfectly valid and good member function name.
    > It's descriptive and concise, and above all, it's abstract. It hides the
    > actual implementation, which is good.
    >
    > If it was somehow named after what it actually does (eg. simply
    > returns a member variable), then what happens if in the future its
    > implementation is changed to something else? Are you going to change the
    > name of the function to reflect that?


    getSomething is technically valid but not good: it's ungood.

    It is a Java'ism. In Java it serves a technical purpose for the kind of
    name you applied it to. In C++ it does not.

    Compare

    getSin(v)*getX()

    to

    sin(v)*x().

    "Get" it?

    Probably not -- you'll get it long after this, and then wonder about
    what you could have been thinking earlier -- but anyway, also consider

    void getLargeDataSet( std::vector<double>& v ) { ... }

    // Wrapper for ease of use, relying on RVO.
    std::vector<double> largeDataSet()
    {
    std::vector<double> result;
    getLargeDataSet( result );
    return result;
    }

    where the two name forms play different roles. If you use "get"
    indiscriminately for a completely (worse than) useless purpose, as you
    did, you lose the ability to use "get" for something useful, as above.


    Cheers, & hth.,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Nov 12, 2007
    #4
  5. Kira Yamato Guest

    On 2007-11-12 13:30:28 -0500, "Alf P. Steinbach" <> said:

    > * Juha Nieminen:
    >> Alf P. Steinbach wrote:
    >>>> int getA() {
    >>>> return a_;
    >>>> };
    >>> The prefix "get" serves no useful purpose. It just clutters the code
    >>> and incorrectly indicates some dynamic action to obtain the value.

    >>
    >> What kind of strange principle is that?
    >>
    >> So what if it "incorrectly indicates some dynamic action"? It's a
    >> public interface. You *don't know* what it does inside. You *don't care*
    >> what it does inside. It could perform an SQL database search for all you
    >> know. The only thing you care is what it's defined to do, ie. it returns
    >> a specified value, and that's it.
    >>
    >> "get<something>()" is a perfectly valid and good member function name.
    >> It's descriptive and concise, and above all, it's abstract. It hides the
    >> actual implementation, which is good.
    >>
    >> If it was somehow named after what it actually does (eg. simply
    >> returns a member variable), then what happens if in the future its
    >> implementation is changed to something else? Are you going to change the
    >> name of the function to reflect that?

    >
    > getSomething is technically valid but not good: it's ungood.
    >
    > It is a Java'ism. In Java it serves a technical purpose for the kind
    > of name you applied it to. In C++ it does not.
    >
    > Compare
    >
    > getSin(v)*getX()
    >
    > to
    >
    > sin(v)*x().
    >
    > "Get" it?


    I think I.get_it(). Oh wait, I meant to say I.it(). Hmm... That
    doesn't look right.

    In the case of sine, sine is really a function object. The () operator
    is overloaded to mean "evaluate this function at". So, the verb
    'evaluate' is implied here. To be verbose, it should've been
    sine.evaluate(v).
    This implied verb 'evaluate' is acceptable here because this is a
    widely accepted mathematical notation. For other stuff, I do prefer to
    use a verb form to state what my methods are doing.

    >
    > Probably not -- you'll get it long after this, and then wonder about
    > what you could have been thinking earlier -- but anyway, also consider
    >
    > void getLargeDataSet( std::vector<double>& v ) { ... }
    >
    > // Wrapper for ease of use, relying on RVO.
    > std::vector<double> largeDataSet()
    > {
    > std::vector<double> result;
    > getLargeDataSet( result );
    > return result;
    > }


    Why not just declare class for the noun 'LargeDataSet' and use the verb
    'getLargeDataSet' for the function instead?

    >
    > where the two name forms play different roles. If you use "get"
    > indiscriminately for a completely (worse than) useless purpose, as you
    > did, you lose the ability to use "get" for something useful, as above.


    --

    -kira
    Kira Yamato, Nov 12, 2007
    #5
  6. * Kira Yamato:
    > On 2007-11-12 13:30:28 -0500, "Alf P. Steinbach" <> said:
    >
    >> * Juha Nieminen:
    >>> Alf P. Steinbach wrote:
    >>>>> int getA() {
    >>>>> return a_;
    >>>>> };
    >>>> The prefix "get" serves no useful purpose. It just clutters the code
    >>>> and incorrectly indicates some dynamic action to obtain the value.
    >>>
    >>> What kind of strange principle is that?
    >>>
    >>> So what if it "incorrectly indicates some dynamic action"? It's a
    >>> public interface. You *don't know* what it does inside. You *don't care*
    >>> what it does inside. It could perform an SQL database search for all you
    >>> know. The only thing you care is what it's defined to do, ie. it returns
    >>> a specified value, and that's it.
    >>>
    >>> "get<something>()" is a perfectly valid and good member function name.
    >>> It's descriptive and concise, and above all, it's abstract. It hides the
    >>> actual implementation, which is good.
    >>>
    >>> If it was somehow named after what it actually does (eg. simply
    >>> returns a member variable), then what happens if in the future its
    >>> implementation is changed to something else? Are you going to change the
    >>> name of the function to reflect that?


    Forgot to answer that, the answer is it depends, and it also depends
    whether it's a good idea to expose implementation strategy via a name.
    Say the original implementation was a simple lookup in a cache, whereas
    the new one does a network database lookup to be Really Really Sure. In
    that case, the new implementation isn't just a new implementation: code
    that relied on the "essentially no cost" of the original will sputter
    and die if the implementation is simply replaced with the new one. It's
    a different function even if it (eventually) achieves the same result.
    So what are you going to name it? The idea that it's "the same"
    function is incorrect, based on an incorrect notion that the network
    database lookup is a purely internal implementation detail: it's not.

    When the naming obscures a detail that is essential to correct usage,
    it's not clear, even if in isolation it might seem to be very clear.


    >> getSomething is technically valid but not good: it's ungood.
    >>
    >> It is a Java'ism. In Java it serves a technical purpose for the kind
    >> of name you applied it to. In C++ it does not.
    >>
    >> Compare
    >>
    >> getSin(v)*getX()
    >>
    >> to
    >>
    >> sin(v)*x().
    >>
    >> "Get" it?

    >
    > I think I.get_it(). Oh wait, I meant to say I.it(). Hmm... That
    > doesn't look right.
    >
    > In the case of sine, sine is really a function object. The () operator
    > is overloaded to mean "evaluate this function at". So, the verb
    > 'evaluate' is implied here. To be verbose, it should've been
    > sine.evaluate(v).


    Yes, I think you got it :) -- that part at least.


    > This implied verb 'evaluate' is acceptable here because this is a widely
    > accepted mathematical notation. For other stuff, I do prefer to use a
    > verb form to state what my methods are doing.


    Well, so does Marshall Cline, the FAQ's author.

    However, my own ideas in this area are based on "readable code", the
    notion that code that can be read straightforwardly tends to be more
    clear than otherwise. Of course, that was also the basic idea of COBOL,
    so it can be implemented in ungood ways: I think it's necessary, but not
    sufficient, for clarity. Adjunct to that idea is the notion of
    /creating a language/ for the reader of the code, that the nouns and
    verbs etc. introduced as names, should make sense, should be eminently
    readable, in the context of code using those names in a natural way.

    So one main guideline for naming is to consider the usage and in
    particular the readability, reading code as almost-natural language, of
    the client code. Consistency is then derived from that goal. I.e., in
    choosing what to be consistent about in naming, the main thing to be
    consistent about should IMO be that names yield readable, clear client
    code, which requires intelligence and thus cannot currently be
    completely formalized in fixed mechanical rules -- using only
    mechanical rules for naming consistency may yield consistency at the
    level of details, elevating those details to so great importance that
    they become a real pain and great distraction, and in general yields
    inconsistency at the level that counts, clarity.


    >> Probably not -- you'll get it long after this, and then wonder about
    >> what you could have been thinking earlier -- but anyway, also consider
    >>
    >> void getLargeDataSet( std::vector<double>& v ) { ... }
    >>
    >> // Wrapper for ease of use, relying on RVO.
    >> std::vector<double> largeDataSet()
    >> {
    >> std::vector<double> result;
    >> getLargeDataSet( result );
    >> return result;
    >> }

    >
    > Why not just declare class for the noun 'LargeDataSet' and use the verb
    > 'getLargeDataSet' for the function instead?


    The above gives the client code a choice:

    * prematurely optimize execution time by using getLargeDataSet(),

    which means introducing an unnecessary variable and writing successive
    interacting statements instead of a single simple expression, or

    * optimize programmer's time by using largeDataSet()

    (no extra variable, expression-oriented code). In general, optimizing
    programmer's time, when including in that future maintainance time, is
    very very seldom premature. It should be the default. ;-)

    And much of what goes on in C++ these days, including C++0x (hopefully
    C++09), is all about achieving expression-oriented, readable, clear
    code, optmizing programmer's time. That's not because of some abstract
    high level ideal, but that practical experience over now about 25 years
    has convinced the best & brightest that writing action-oriented
    statements that interact via variables, leads to complexity, bugs and
    much wasted programmer's time. Expressions are the new Great Thing(TM).


    >> where the two name forms play different roles. If you use "get"
    >> indiscriminately for a completely (worse than) useless purpose, as you
    >> did, you lose the ability to use "get" for something useful, as above.


    Cheers,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Nov 13, 2007
    #6
    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. tirath
    Replies:
    3
    Views:
    697
    Ivan Vecerina
    Oct 12, 2003
  2. Replies:
    1
    Views:
    387
    myork
    May 23, 2007
  3. Replies:
    1
    Views:
    374
    Victor Bazarov
    May 23, 2007
  4. Replies:
    5
    Views:
    500
    Ian Collins
    Nov 12, 2007
  5. David
    Replies:
    3
    Views:
    393
    Grizlyk
    Jan 29, 2008
Loading...

Share This Page