Back to Basics: Designing Classes (part 2 of 2) - Klaus Iglberger - CppCon 2021

Поделиться
HTML-код
  • Опубликовано: 6 ноя 2024

Комментарии • 51

  • @mehtubbhai9709
    @mehtubbhai9709 2 года назад +23

    These 2 talks are the things that I have had to find in many different places over time but now conveniently and wonderfully presented here. Thanks again Klaus!

    • @CppCon
      @CppCon  2 года назад +2

      Glad it was helpful!

  • @fillername4223
    @fillername4223 Месяц назад

    Both parts were bloody great, thank you for your work Klaus!

  • @artus9022
    @artus9022 2 года назад +25

    This talk was kinda eye opening. A lot of stuff i have never thought about, like ordering the members.
    Thank you very much!

    • @lehaipham4622
      @lehaipham4622 2 года назад

      And also the war between West Coast vs East Coast. So happy to watch this.

  • @kabasakalis
    @kabasakalis 2 года назад +8

    This guy is amazing. Such clarity. Great instructor.

  • @Dziaji
    @Dziaji 2 года назад +5

    If you initialize in a different order than you declare, it is not a compilation error. The order of your initialization statements is simply ignored and the compile initializes in the same order that you declared. Think of it like the compile reorders your initializer statements to match the order of the declarations. It will warn you because the statements will be executed in a different order from how they are listed in the code, and this can be confusing for someone that doesn't understand this nuance, especially if the initialization of certain members has side effects outside of the class, or if one member is initialized based on the value of another member. For example, in the following class, m_P2 will always be uninitialized after the default constructor is called, even though it looks like it should point to m_Data like m_P does:
    struct MyClass {
    int m_Data, *m_P2, *m_P;
    MyClass() : m_Data(5), m_P(&m_Data), m_P2(m_P) {};
    };

  • @LiveseyMD
    @LiveseyMD 2 года назад +2

    This one is absolute practical gem! Just because these guideline can and should be used for already existing code base.

  • @AvijeetMaurya
    @AvijeetMaurya Год назад

    Great talk! I didn't knew the difference between visibility and accessibility till now.

  • @lehaipham4622
    @lehaipham4622 2 года назад +3

    Another piece of gold from Klaus! I follow this from part 1 and it does not let me down.
    I will definitely go through the Cpp Guidelines, it should be a gold mine there to dig.
    Thank Klaus and CppCon for making this available.

  • @fouksmam
    @fouksmam 2 года назад +1

    Great talk, Klaus. Very insightful. Thank you

  • @sanjaygatne1424
    @sanjaygatne1424 2 года назад +1

    very neat explanation. expecting more talks.

  • @MasteringCodeInterviews
    @MasteringCodeInterviews 2 года назад

    Really enlightening talk.Thanks a lot cppcon and klaus!

    • @CppCon
      @CppCon  2 года назад

      Thank you very much for your appreciation.

  • @samuelpolacek6762
    @samuelpolacek6762 2 года назад

    People playing with Pahole in Godbolt will appreciate -Wpadded compiler option as well. Thanks for the talk!

  • @konstantinburlachenko2843
    @konstantinburlachenko2843 2 года назад +2

    The most fancy thing that I saw in C++ is try/catch for initialiser list.
    #include
    class C
    {
    public:
    C() try : a()
    { puts("C()"); }
    catch(...)
    { puts("WOW!"); }
    int a;
    };
    int main()
    {
    C c;
    return 0;
    }

  • @badassopenpolling
    @badassopenpolling 7 месяцев назад

    Kindly post a link to Core Guidelines !!!!

  • @rahul_walse
    @rahul_walse 2 года назад

    Thank you for a very detailed and informative session. So much to learn!

    • @CppCon
      @CppCon  2 года назад

      You're very welcome!

  • @Fetrovsky
    @Fetrovsky 2 года назад +1

    Why do you need const versions of begin()/end() _and_ cbegin()/cend() as well?

    • @Fetrovsky
      @Fetrovsky 2 года назад +3

      Answer is at the end of the video: If you are in a non-const context, you can get const iterators by calling cbegin()/cend(), whereas begin()/end() will return non-const iterators in that situation.

  • @antonfernando8409
    @antonfernando8409 2 года назад

    "Encapsulating Design decisions" around 47:37, what does it mean by encap design decision , and what it got to do with iterators? Thanks.

    • @pedrovictor8666
      @pedrovictor8666 2 года назад +2

      The design decision made is regarding the data being stored and the return type of the begin/end member functions.
      The example he represented returns pointers. Pointers are a valid return type because they have the required interface for being iterators, that is, they can be post-incremneted ( as in ++p) and can be compared (as in current != end).
      However, if he decides that his Widget (or whatever class he used as the example) now does not store the data in a contigously, (as an plain array, or vector, for example), the pointer will not be able to iterate over the elements, because incrementing the pointer now does not give the next element. This has to do with how iterators are implemented... they expect that post-incrementing will return the next element.
      So, by explicity returning a pointer, information about the underlying structure (the contigous data) is leaked. By using the typedef, users of the code will now not store the return result of begin() in a pointer type, but in a Widget::iterator_type. Should the Widget class be modified, the typedef would be modified accordingly, and the user code would not need to change.

    • @antonfernando8409
      @antonfernando8409 2 года назад

      @@pedrovictor8666 Thanks.

  • @mehtubbhai9709
    @mehtubbhai9709 2 года назад

    @Klaus. If you had yr choice of programming styles in a new bluesky project, would you still prefer to use free functions over member functions?
    The "Free your Functions!" talk you gave a while back settled it for me ;)

    • @Dziaji
      @Dziaji 2 года назад +1

      It depends. Sometimes you want to use member functions, like if you have a complex, delicate data member that you want to remain private. The functions that mutate such a private member make sense to be private member functions because you don't want the data getting corrupted by improper use of those functions. For example, if you are writing a hash map, the data needs to be properly stored, and you don't want consumers of the class manually calling a function that will free the heap memory that stores the objects. You would make a private member function called "Destroy()" and call it in your destructor and assignment member functions. That way your data is protected and no one is able to accidentally free the memory of an instance that is still alive.
      Also if you need to distinguish which derived class type the instance that is pointed to by a pointer of the base class type is, you either need to store an extra piece of data in the class to make the distinction using "if" statements in free functions, or the better way, which is to make a virtual member function that you can just call from the base class, and it will automatically remember which derived class the instance belongs to.
      Free functions are great if you want to encourage extensibility in your class, so that the extendible parts exist in free functions that can be overloaded separately from the class, or if you want to extend a class into a paradigm that is separate from the class (like writing a pretty_print_me(T& data) function). In that case, you don't necessarily want to jam all of your outside paradigms into the class definition and clutter it up.
      Another reason that members are really good to use is that things like intellisense work better for member functions than they do for free standing functions. if you type "object." you will get a list of member functions that can be called on the class in most modern IDEs. This can be handy if you are thinking "I know there is some function to use to flag this game state object as 'level complete', but I forget what it is called". If you wrote it with free functions you will have to actually check the header file for the class instead of just typing "object." and looking through the options.
      So I guess some good rules of thumb are:
      1. Use free functions for functions that will be implemented for many classes like "pretty_print()" or "serialize()" or "find" or "reverse", because in that way, your free function overloads become a kind of cross-class paradigm, and you can bring classes that you don't control the code for into that paradigm so that they can be used in this paradigm in an indistinguishable way from the classes you do control. (I believe this is why "std::vector::begin()" is now a deprecated paradigm in favor of "std::begin(std::vector&)")
      2. Use free functions for paradigms in classes that you control that you expect other people to extend. A somewhat complex and contrived example of this might be a "copy_from()" function that takes other types, and copies their data and converts and assigns the data to your class. Make your assignment operator a template that accepts any type like this:
      template YourClass &Operator=(const T ©able) {
      destroy();
      copy_from(*this, copyable);
      private_member_function();
      return *this;
      };
      and now anyone can effectively hook their class to you implementation, and it will be treated just like they were able to add an overload to your assignment operator, without actually giving them access to your private methods by making them public. All they have to do is simply define a function like:
      void copy_from(YourClass &to, const TheirClass &from) {
      for (auto &e : from) to[e] = TheirClass::ConvertElement(from[e]);
      }
      So by controlling which functions are free, and which aren't, you are delegating which aspects of your class are extensible and which aren't.
      3. If you have sensitive functions that make sense to be private, keep those as private member functions.
      4. If you have a lot of features to your class that would benefit from intellisense, make those public member functions.
      These aren't all the considerations, and there is no law on any of this. On a function by function basis, analyze which makes more sense for that function based on how that function might be used, misused, and extended.

  • @masheroz
    @masheroz 2 года назад

    At 48:00. What happens if you change the iterator to return a reference? Then calling code that dereferences the iterator will now break?

  • @jaggis4914
    @jaggis4914 2 года назад +1

    Interesting session! Thanks

    • @CppCon
      @CppCon  2 года назад

      Thank you for your comment.

  • @MagnificentImbecil
    @MagnificentImbecil 2 года назад

    Also, bitfields are dangerous when it comes to concurrency (being accessed from multiple threads): Bitfields are usually not "separate memory locations". @2.27

  • @voltairespuppet
    @voltairespuppet 2 года назад

    At 51:58 shouldn't that be Widget(double const& d)?

    • @thomasw813
      @thomasw813 Год назад

      No. If you do that, you can't have the function that returns the non-const double&.

  • @Reneg973
    @Reneg973 2 года назад

    I'm still unsure regarding the const member variables. I found when I design a class with such a member, that this mostly are classes which should not be copied. In this case I also don't need to explicitly delete the copy constructor.

    • @masheroz
      @masheroz 2 года назад

      Not being able to modify a class instance is different to not being able to copy one.

  • @ska4dragons
    @ska4dragons 2 года назад

    My new cppcon friend's other sleeve slides up accidentally.
    Me: *gasp* "The betrayal!"

  • @flocela
    @flocela Год назад

    glass Widget - funny! : )

  • @TestDrivenDeveloper
    @TestDrivenDeveloper Год назад

    Great

  • @willculpepper9637
    @willculpepper9637 2 года назад

    36:50 Ha! It's recreational factionalism

  • @ledi51
    @ledi51 2 года назад

    Here for the const wars

  • @JusticeHunter
    @JusticeHunter 2 года назад +2

    West-Coast const and East-Coast const are a mouthful, why not just say East const and West const :D

    • @Fetrovsky
      @Fetrovsky 2 года назад

      That's how I refer to them.

  • @konstantinburlachenko2843
    @konstantinburlachenko2843 2 года назад

    In slide 45 misprint - exit_success probably is not a thing to return

    • @thomasw813
      @thomasw813 Год назад

      EXIT_SUCCESS and EXIT_FAILURE are defined in header cstdlib and it's a typical return value for the main() method. It doesn't work for the chevron operator here.

  • @videofountain
    @videofountain 2 года назад

    At the point ... ruclips.net/video/O65lEiYkkbc/видео.html .. Slide 54 ...int const* const ptr2; ... Is this intentional?
    Is this an uninitialized const variable?

    • @thomasw813
      @thomasw813 Год назад

      I think it is an uninitialized const variable. Just like std::unique_ptr const ptr1; As long as it's not used, that's fine. Is this intentional? Probably, for the sake of shorter code on slides.

  • @alexandre8350
    @alexandre8350 2 года назад

    why are good practicies like this have 4k views ?

  • @adrianhurtado8323
    @adrianhurtado8323 2 года назад

    Funny detour on east and west coast const.

  • @jhbonarius
    @jhbonarius 2 года назад

    I started writing all local object declarations like "auto widget{Widget{}};" that way you can never forget initialization.

    • @dagoberttrump9290
      @dagoberttrump9290 2 года назад

      That's probably slower because it is performing copy initialization

  • @greob
    @greob 2 года назад

    Nice presentation, easy to follow and understand.