Back to Basics: Object-Oriented Programming - Jon Kalb - CppCon 2019

Sdílet
Vložit
  • čas přidán 14. 05. 2024
  • CppCon.org
    -
    Discussion & Comments: / cpp
    -
    Presentation Slides, PDFs, Source Code and other presenter materials are available at: github.com/CppCon/CppCon2019
    -
    Modern C++ is at its best when using generic and/or functional programming filled with techniques to squeeze the greatest possible performance with the latest compile-time features.
    But millions of C++ programmers are still using C++ the old-fashioned way, designing, building, and most importantly, maintaining object-oriented hierarchies based on virtual functions and run-time polymorphism. Some of these programmers don’t know a different way and some would love to start from scratch with a more modern approach, but they all share something in common. They all want to build the best code they can with the paradigm they are are using.
    Object-Oriented Programming was state-of-the-art C++ programming for decades and industry best practices developed to produce high-quality code and avoid practices that lead to buggy, hard-to-maintain code. With billions of lines of OOP code in C++ currently in production, someone should be talking about OOP best practices, because old-school doesn’t mean easy. But OOP just isn’t trendy anymore.
    In this session, instead of lecturing you that you shouldn’t be using OOP, I’m going to share the industry best practices developed during the last four decades and updated to latest language features.
    -
    Jon Kalb
    Jon Kalb, Consulting
    Conference Chair
    Silicon Valley
    Jon has been programming in C++ for almost three decades and does onsite training for teams that want to up their C++ game.
    Jon chairs C++Now, CppCon, the C++ Track of the Silicon Valley Code Camp, and the Boost Steering Committee. He also serves on the board of directors for the C++ Alliance.
    Jon is a frequent speaker at local user groups and conferences, including C++ Russia, where he gave the keynote address in 2018 and C++Now where his talk on Exception-Safe Coding won Best Tutorial.
    -
    Videos Filmed & Edited by Bash Films: www.BashFilms.com
    *-----*
    Register Now For CppCon 2022: cppcon.org/registration/
    *-----*

Komentáře • 56

  • @elijahshadbolt7334
    @elijahshadbolt7334 Před 4 lety +16

    I always like listening to these talks, because of the sensible guidelines, and the small revelational details mentioned in passing.

  • @superscatboy
    @superscatboy Před 2 lety +10

    Fantastic to hear a talk about how to make object hierarchies work rather than just saying they don't work and ignoring the subject.
    Every paradigm works if it's implemented well, and every paradigm is broken trash if it's implemented badly.

    • @jonkalb2746
      @jonkalb2746 Před rokem

      I agree.

    • @darkengine5931
      @darkengine5931 Před rokem

      ​@@jonkalb2746 I rather disagree. I think certain paradigms are vastly more productive for certain applications. OO has its ideal use cases, just as procedural, functional, logical, reactive, etc. One of the things I appreciate most about C++ is that it does a decent job of supporting all of them (although a bit clunkier for declarative paradigms, but still usable). I often hear it repeatedly said that a programmer isn't defined by his tools with which I wholeheartedly agree, but at the same time an oil painter who tries to bring the mentality of fat-over-lean oil painting principles to a scenario that wants a watercolor result is going to do a very poor job. Certain tools/methodologies are better for certain jobs, and I think too often this style of thinking that a programmer should be able to use any tool for the job is missing out on the fact that certain tools are more appropriate for certain jobs.

  • @OperationDarkside
    @OperationDarkside Před 4 lety +29

    Good overview for beginners. I wondered why eclipse wanted me to make my destructor virtual, now I understand.

    • @seditt5146
      @seditt5146 Před 4 lety +6

      Only have way through and I can think of plenty of nonbeginners that can use this talk. Hell I find value it in, always good to get back to basics and review esp since the language is ever morphing.

    • @jonkalb2746
      @jonkalb2746 Před rokem +3

      @@seditt5146 Thanks for your kind words.

  • @codeloners6820
    @codeloners6820 Před 7 měsíci

    Jon Kalb is a great teacher! Very well explained even for c++ beginners like me.

  • @dimitriosmenounos1009
    @dimitriosmenounos1009 Před 2 lety +1

    24:00 The NVI idiom is basically a specialized form of the template pattern, which in turn is a variation of the proxy and adapter patterns.

  • @MagnificentImbecil
    @MagnificentImbecil Před rokem +2

    Regarding the question at 55:07: "If the class has at least one virtual function, [given that polymorphical deletion (i.e. `delete pBase;`) with a non-virtual destructor in the base class produces Undefined Behaviour, ] why is the destructor not virtual by default ?",
    I would like to note something learned from the essence of COM (Component Object Model).
    One purpose of COM is to create binary inter-operability of machine code generated by various toolchains (actually extending to various languages besides C++).
    Most C++ toolchains, given a class with non-destructor virtual functions, place a vptr as a first hidden member in the object and place pointers to the virtual functions in the vtable, one pointer per virtual function, in the order that the virtual functions are declared in the base class. The ABI is, at least de facto, well-defined. (Add to that the fact that COM uses __stdcall everywhere.)
    Not so with the virtual destructor !! For the (single) virtual destructor, some toolchains use one entry in the vtable (and the destructor has a hidden parameter, which could be of type bool or of type std::size_t) and other toolchains use two entries in the vtable (roughly corresponding to the other toolchains' bool parameter being false and being true).
    These differences affect binary compatibility (of loader-modules created with distinct toolchains).
    COM proposes a different, actually more flexible (if more cumbersome to use) mechanism that client-code should use instead of `delete pInterface;` -- and that is `pInterface->Release ();`, with Release being a virtual function. Implementations of Release often might use non-polymorphical deletion, e.g. `delete this;`. As an example of flexibility, they might also be no-operations.
    Sidenote: Now client code no longer even needs to use the same allocation/deallocation code as the implementation.
    We can also use `shared_ptr` with custom deleter for similar reasons/purposes.

    • @darkengine5931
      @darkengine5931 Před rokem

      That's a great point WRT to ABI and something I didn't realize (we export C APIs with dylib exports and function pointers instead to completely avoid getting into trouble with vtables or exceptions or varying C++ standard library implementations or anything which could destroy ABI). I think also it's trivial to make a base class provide a non-virtual dtor and still be safeguarded by the compiler. We merely make the destructor protected, and now we no longer have the ability to destroy instances of its subtypes through a base pointer.

  • @andreasfett6415
    @andreasfett6415 Před 4 lety

    Hi Jon,
    My main motivation to use abstract interfaces is to be able to mock them out for unit tests. I know there are compile time polymorphism approaches to this, but they have drawbacks (mainly exposing their dependencies). Is there a proper way to deal with this when using an NVI design and also using dependency injection? Because at the end of the day I still prefer a system that has easy unit test implementations to anything else.

  • @robertramey5169
    @robertramey5169 Před 4 lety +4

    Great presentation for real programmers ! I thought I knew this stuff but I didn't really. I'm still attracted to the idea of using inheritance for code reuse - but I better understand the argument against it.
    Might it be a good idea to delete the operator*() on the base class to prevent/detect many of these problems?

    • @jonkalb2746
      @jonkalb2746 Před 2 lety +2

      Robert, I believe the operator*() would only be called if you wanted to dereference the base class object itself (as if it were a smart pointer), not to access the object through its address.
      Deleting the address of operator ( Base* Base::operator&() = delete; ) might prevent some abuse, but it would also break code that tried to take the address of a base class reference, which is valid and safe (assuming the address is not subsequently used in improper ways).
      Thanks for the suggestion.

  • @victotronics
    @victotronics Před 2 lety +3

    Can a Kool Kid show me how to solve the traveling salesman problem at compile time?
    And argue that it's better than solving it at runtime?

  • @FreeScience
    @FreeScience Před rokem

    What does it mean to use virtual in the implementation of a member function in the concrete class 6:37?

    • @FreeScience
      @FreeScience Před rokem +2

      Got it from watching the rest of the video :)

  • @jvsnyc
    @jvsnyc Před 3 lety +3

    At ~24:53, do we really mean to make DoLogMessage() private and virtual? I am confused.

    • @jvsnyc
      @jvsnyc Před 3 lety +5

      This was my bad. Newbies to C++ often think that you can't have private virtual functions in base classes. You can. Derived classes will not be able to CALL them, but can certainly override them effectively. The Template pattern/Non-Virtual Interface pattern is exactly where we make use of it. Now, in Java, there is no way for a sub-class to to override a private method, not only can they not call them, they can't override them either. So rather than saying "C++ newbies don't realize you can override private member functions of a super-class", I would say "C++ newbies and those who have been spending more time in Java than C++ lately". Attempting to override a private base class method is one of many errors that you can get caught out on in a Java certification exam. Some of these things you wonder why they are thinking you will think you can do that -- in this case it could be that a Java programmer has been spending so much time lately in C++ they forget that Java found that confusing and forbade it. Their OOP models are exactly the same, except for the many differences, not just 'interfaces instead of multiple inheritance' as some people like to try to summarize it.

  • @DerHerrLatz
    @DerHerrLatz Před 4 lety +20

    Using virtual and override in the same line feels a bit redundant.

    • @Possseidon
      @Possseidon Před 4 lety +8

      Yeah, the core guidelines actually recommend using exactly one of virtual, override or final.

    • @sspitfire777
      @sspitfire777 Před 3 lety +3

      When you declare the function virtual and override, compiler will actually throw an error if there is a syntatic issue in your code related to that function

    • @llothar68
      @llothar68 Před 3 lety +3

      @@Possseidon And anotehr guideline i won't obey. Virtual is in front, override at the end so reading is more easy with virtual and it also means something different.
      Just to safe a few keystrokes. Get rid of this terrible templated pointer shit code before you take away virtual.

    • @RenamedChannel
      @RenamedChannel Před 3 lety

      @@llothar68 Checkmate
      struct B { virtual void func(); };
      struct D : B { virtual void funk() final; };

    • @jonkalb2746
      @jonkalb2746 Před 2 lety +1

      @@RenamedChannel I don't know of any use case for "final" when used on a function, only when used on a class. I don't understand the semantics of such use.
      What does this mean?
      Until someone can explain this to me, you won't see it my code or any code I've reviewed.

  • @jensBendig
    @jensBendig Před 3 lety +1

    Good talk. I have to hear a lot of rubbish about oop from a lot of guys who barely get the meaning of "instance". You say it: There are a lot of underlying concepts that we should talk more about.

    • @jonkalb2746
      @jonkalb2746 Před 2 lety

      Jens, thanks for your kinds words.

  • @CookiePepper
    @CookiePepper Před 2 lety +1

    The problem of the OOP is that the OOP became the object instead of just a tool for better programming.

  • @image_amkerp2872
    @image_amkerp2872 Před 2 lety +2

    while (true)
    { Thanks a lot )

    • @jonkalb2746
      @jonkalb2746 Před rokem +1

      @image_am kerp, Thanks for the kind... umm... code?

  • @distrologic2925
    @distrologic2925 Před 4 lety +14

    We really need a new name for this concept instead of "object-oriented Programming". There are a lot of differentiated concepts thrown around with this name, which really doesn't describe anything anymore apparently.

    • @jonkalb2746
      @jonkalb2746 Před 2 lety +4

      I understand your frustration with this (I've felt it myself), but it is the "term of art" and thousands of academic and non-academic papers/articles have been written using this term. We could come up with a new name, but the old term will be forever with us, so I think it is better to explain what the term is understood to mean than to have to introduce a new term and then explain that the new term means the same thing as OOP.

  • @Asmaddeus
    @Asmaddeus Před 3 lety

    At 41:37, I think it should be ConsoleLogger cl{"logfile.txt"};
    FileLogger class is not defined and cl means ConsoleLogger.

    • @ABaumstumpf
      @ABaumstumpf Před rokem

      He showed FileLogger early at 9:14 so it should have been:
      *FileLogger fl{"logfile.txt"}; *

  • @BosakMaw
    @BosakMaw Před 3 lety +1

    At 24:47 why is DoLogMessage private, how are derived classes going to implement it? Shouldn't it be protected instead or am I missing something?

    • @jonkalb2746
      @jonkalb2746 Před 3 lety +6

      Derived classes are free to **override** private virtual member functions even though they are private. They cannot call them, because they are private. If we thought that derived classes might need to call DoLogMessage(), then we'd need to make it protected.

  • @edwardyang8254
    @edwardyang8254 Před 2 lety

    I've never seen a useful C++ program without a class. I don't know how you can use class without the fundamentals of OOP.

  • @-taz-
    @-taz- Před 4 lety

    If we pass a logger into any object, then that object will have 2 separate responsibilities.

  • @darkengine5931
    @darkengine5931 Před rokem +2

    One reason my industry (games) is moving away from OOP -- especially the type mentioned here which aims to model "is-a" relationships in object hierarchies and even pure interfaces -- is that it's far too rigid and inflexible to rely on "is-a" relationships between types (even pure interfaces) against the most complex design and changing needs. They don't properly model the adaptability and complexity of the real world.
    For example, the reason a human can walk is not because it's a biped. It's because it has functional legs, and some humans don't even have them and can't walk. A duck can fly not because it's a bird, but because it has functional wings just like an airplane which isn't a bird, and unlike airplanes, it can also walk because it has functional legs.
    And in modern game engines, the design needs are so complex and ever-changing that it's virtually impossible to design very stable inheritance hierarchies for their game entities. For a simple (contrived but simple) example, a game might assume that plants and animals are separate and distinct types of objects at the same level of the hierarchy, and it may seem like a firm and sensible assumption to make that an entity can be either a plant or an animal but not both. Yet 2 years after shipping, the designer might suddenly want our game to feature a fantasy creature that has the characteristics and behaviors of *both* plants and animals. If we designed our architecture using inheritance, we may find that we need to rewrite an enormous amount of code or put difficult-to-maintain workarounds into the system to handle this seemingly simple design change.
    So OOP, and most specifically inheritance, tends to be too rigid and inflexible for our ever-changing design needs; it tends to work best when all the design needs can be anticipated upfront but the implementation details can't be (the logger is a good example, as the full design requirements of all possible users of loggers is not only possible but trivial to anticipate upfront).
    Yet games have extremely complex and ever-changing design-level needs similar to the real world, as they often aim to simulate them, and so they not only need extreme implementation flexibility but also extreme breathing room for unanticipated and extremely late design changes (extreme decoupling). The real world doesn't work according to inflexible "is-a" relationships to determine functionality and behavior. It works according to extremely flexible "has-a" relationships as we find in composition, and not just static composition but dynamic composition where components can be added and removed on the fly and queried for availability at runtime (ex: a human can have legs which allow him to walk until he gets injured and requires them to be amputated at which point he will lose not only the functionality of his legs but the data is removed from him as well).
    Even the simplest indie game which implements Dungeons & Dragons rules will find OOP inappropriate to implement the perfectly-detailed rulebook which provides all the design requirements upfront, as the way D&D is designed groups components together based on the fact that they share the same data (ex: all weapons share the same fundamental data, but some may have a fire damage component), not based on sharing the same abstract interface -- the data is the interface in D&D, and that's how most game designers think and request design changes. It's built around what things have, not what things are. Anyway, apologies for the ramble but it's strange to me that so many computer scientists still think games are an ideal application not only for OOP but inheritance when it's probably one of the worst places to use OOP, even for a simple D&D game.

  • @interrogationwatch3781
    @interrogationwatch3781 Před 2 lety +1

    If OOP is good why is life procedural?

    • @jonkalb2746
      @jonkalb2746 Před rokem +2

      Like any other model, OOP isn't an exact likeness of reality. It is up to us as engineers to determine how and how well the model works for solving the problem at hand.

  • @neon_code
    @neon_code Před 2 lety

    So oop is no more oop.

  • @ZahrDalsk
    @ZahrDalsk Před 2 lety

    What he's describing here isn't object-oriented programming. Reported for misleading title.

    • @jonkalb2746
      @jonkalb2746 Před 2 lety +4

      @ZahrDalsk, industry and the academy have used the term "object-oriented programming" (from the time of its invention by Dahl and Nygard with Simula 1) to refer to what I'm describing in this video.
      If you have another idea of what this term means, I suggest that you may be out of step with industry and the academy.
      If your point is that this term doesn't clearly suggest this programming paradigm, I'm sympathetic. But my opinion wasn't solicited.

    • @MagnificentImbecil
      @MagnificentImbecil Před rokem +2

      The video also has a clear description (mentioning "runtime polymorphism") and a clear introduction (defining "object-oriented C++"). We know what we are in for.

  • @SteelBlueVision
    @SteelBlueVision Před 4 lety +8

    I gave this video a downvote.
    I think the material presented here is completely misleading and a waste of time for even a novice C++ developer, since it is so basic and fundamental and presented in no clear logical order. Additionally, most of the material presented here is not actionable (today), is a complete waste of one's time, and makes one's code worse and not better as the author claims. This is not because most if not all of the ideas were not sound a decade or two ago when the books on which they are based were written, nor is it because of some flawed notion by some ignorant developers that OO programming as a whole is "outdated." No, the reason is that most of the contortions and "extra code" that the presenter implores developers add in order to avoid problems is completely unnecessary and just pollutes said code (and design). Any C++ compiler and even ones from a decade ago would flag most of the problems presented as warnings if and when they occur in modern C++ code. Today, this is combined with the fact that any modern C++ IDE would flag these problems immediately as one types, without even having to wait for a compilation cycle.
    Therefore, forcing the developer to write extra code, and to thereby add additional complexity to one's code, in order to avoid (potential) issues that "may" cause bugs going forward, when any modern C++ compiler/IDE would catch said issues and flag them as warnings if and when they occur is a huge waste of time and mental effort. Additionally, some of the ideas (e.g., non-virtual public functions that call protected virtual functions) as a general principle for *all* cases, makes code flow more complex and less readable and classes more "heavy," and the compilation cycle slower. One can easily lose their train of thought as they move through a multi-function call chain (i.e., a public member function that calls a protected member function and does nothing else, etc...) in order to get to the meat of the code that actually implements a particular functionality. Modern code is convoluted and hard to follow as it is, without making the matter worse through the artificial addition of various contortions that add no functionality. This can be likened to the teaching of database normal forms which now go up to seven and beyond. Yet, no reasonable DBA would design beyond Third Normal Form in actual DB Schema design (for reasons you can read about elsewhere - hint complexity and performance). The author would have been far better off preaching the value of good variable names, proper comments that document classes, polymorphism's applicability and inapplicability vs composition via templates, the (modern) notion of concepts to really protected code functionality from misuse, etc...
    The actionable ideas in this talk (e.g., virtual destructors, etc...) are so basic and fundamental that they are presented in any modern instructional C++ book/course at the very beginning - Chapter 1 material. Even beginner C++ developers learn these concepts very early in their careers, probably within the first days of a job as a C++ developer, if not by reading any sound OO/C++ educational material and/or other modes of proper instruction. A one page document could have been created that summarized all of the actionable items presented, which could be read inside of five minutes, rather than wasting an hour of developers' time on this wordy talk. In fact, this already exists and is called the C++ FAQ. Read it at isocpp.org/faq and take a pass on this video.

    • @jonkalb2746
      @jonkalb2746 Před 4 lety +29

      SteelBlueVision, I suspect that it isn't a surprise that I don't agree, but I appreciate your thoughtful comment.

    • @vladimirkraus1438
      @vladimirkraus1438 Před 4 lety +18

      I assure you that most beginners will find this useful. I know even quite experienced programmers who notoriously get inheritance wrong. I recall for example when I was facing the problem described at time 20:15 in a complicated class hierarchy in a large legacy application. Solving it was a nightmare that took a month and we all just have to pray we did not break anything.

    • @ChopsTwo
      @ChopsTwo Před 4 lety +11

      by golly by gee i wish the companies i've worked at were full of people like you who found all this stuff so obvious and trivial!!

    • @jeremymeiers5977
      @jeremymeiers5977 Před 4 lety +5

      Having liked the video (it saved me by pointed out why I should not make my leaf class a base class, as I just did), I was irritated by this comment. My main issue is that this video for being exactly about what is said it was going to be about in the first minute of the presentation, so I cannot see how this would be an hour wasted, if you are spending too much time watching CZcams videos (as I do) than that is our responsibility.
      If I understand you correctly, SteelBlueVision, your argument is mainly against using NVI everywhere. I can follow your argument somewhat, although most modern IDEs would allow you to quickly go from the non-virtual to the virtual function, and anyhow, if you have to look at the implementation of the interface to understand the code, ... welcome to the Real World. Jon Kalb might for example, have pointed out that NVI makes it harder to ensure you do not call a virtual function in a constructor.
      Anyhow, thanks for both the video and the comment.

    • @andreasfett6415
      @andreasfett6415 Před 4 lety +13

      SteelBlueVision, I still work with "C++ is just C with syntactic sugar" programmers - and I think, they are good programmers. They are just not used to C++. You just can't send them to a C++ 101 starting with "This is a for loop". Also I don't follow your "IDE says its wrong" argument as I expect a programmer to know the "why" and this talk explains it. I don't want developers just blindly trying to elimenate red curly lines. I'm quite happy that Jon does not brush this off with an "Ah! kindergarden knowledge" attitude.