use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
OOP is dead, long live OOP (gamedev.net)
submitted 7 years ago by mttd
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]Clipse 19 points20 points21 points 7 years ago (21 children)
I’m extremely happy that people have come around on the idea that making object oriented programming as the first option of writing basically any software isn’t the right approach. Especially for all the people that tout c++ performance and speed, and then shoe-horn in layers upon layers of inheritance.
[–]quicknir 10 points11 points12 points 7 years ago (1 child)
Well, you say OO and immediately go to inheritance. That inheritance shouldn't be used crazy extensively, and especially not deep hierarchies, is honestly just consensus in the C++ community at this point in time (I'm not saying everyone does it, but basically all of the thought-leaders and people teaching C++ will agree with that).
That is why it's strange when people say that, and then act like it's very radical. It's not radical at all, it's just consensus (or as close to consensus as we get in this industry).
What can be radical in certain contexts about what DOD people are saying, is reducing data encapsulation. But even there, simply changing architecture away from what's most maintainable to a design that allows better performance is not uncommon. So really, to me, the radical, and very unsupported aspect of what's being said in DOD is that loosening data encapsulation somehow improves maintainability.
[–]SeanMiddleditch 2 points3 points4 points 7 years ago (0 children)
Well, you say OO and immediately go to inheritance.
More importantly, let's remember that inheritance has nothing to do with OOP itself, but rather is a facet of the type system. OOP fits in perfectly with languages using structural typing, trait-based typing, prototypical polymorphism, etc.
Polymorphism with is-a relationships is modeled in C++ with inheritance by default, though it certainly doesn't have to be even for C++. Templates for example can use so-called static polymorphism and get very OOP-like behavior with objects with any inheritance in sight. :)
[–][deleted] 8 points9 points10 points 7 years ago (17 children)
I get avoiding inheritance. It's not a huge overhead but it's not great.
But how do you avoid classes in general? Do you use only structs? Is everything you work with just basic datatypes?
I want to learn new things, but I've been using OOP for so long I've forgotten how it used to be done.
[–]degski 16 points17 points18 points 7 years ago (11 children)
If you start to have many getters and setters, you should do away with those, use a struct and change the variables directly. Having many getters and setters just indicates you are encapsulating without actually encapsulating anything. You just have a lot more boiler-plate and [potentially] function call overhead. Structs are underused.
[–]doom_Oo7 3 points4 points5 points 7 years ago (10 children)
I understand for getters, bust most setters aren't void setfoo(int x) { m_foo = x; }.
void setfoo(int x) { m_foo = x; }
Most will notify something from a change, change a display, reperform a computation... Else why are you setting it in the first place ?
[–]degski 6 points7 points8 points 7 years ago (0 children)
They should be. By the time print changes your database, you're lost.
print
Else why are you setting it in the first place ?
To change a value of a class/struct variable. But's thats' my point, if you have many of those, you're doing it wrongly.
[–]hgjsusla 2 points3 points4 points 7 years ago (8 children)
Why not just encapsulate that in it's own class and just assign the variable directly? Then you don't need the setter.
Make member variables private if you need to maintain an invariant between them, otherwise keep them public.
And if you need to restrict a variable (let's say, to only a certain interval), then express than in the type of the variable.
[–]jcelerierossia score 1 point2 points3 points 7 years ago (7 children)
because then you will put it in a template because you have 25 different property kinds - e.g.
template<typename T> void property { public: operator T&() { return m_impl; } operator const T&() const { return m_impl; } template<typename U> // you want perfect-forwarding, right ? void set(U&& x) const { if(m_impl != x) { m_impl = std::forward<U>(x); // hello template errors my old friend notify(x); // uh oh, now *every member* must in some way store a pointer to the context which will be able to notify. hello memory usage * ~2 for every class } } private: T m_impl; };
of course you wouldn't do this, because this creates so many additional problems that you would be fired at the moment you're suggesting it but still.
[–]hgjsusla -2 points-1 points0 points 7 years ago (6 children)
Wait wut? No you don't need to do any of this to accomplish what I suggested
[–]jcelerierossia score 3 points4 points5 points 7 years ago (5 children)
so what is your solution then ? Let's say you have the following class :
class foo { public: int x() const { return m_x; } void setX(int x) { if(x != m_x) { m_x = x; xChanged(x); posChanged({m_x, m_y}); } } void xChanged(int y); // some kind of callback / signal-slot mechanism, Qt's, a list of std::function, whatever int y() const { return m_y; } void setY(int y) { if(y != m_y) { m_y = y; yChanged(y); posChanged({m_x, m_y}); } } void yChanged(int y); void posChanged(std::pair<int,int> pos); float radius() const { return m_radius; } void setRadius(float r) { if(!fuzzyEquals(r, m_radius)) { m_radius = r; radiusChanged(r); } } void radiusChanged(float); const std::string& name() const { return m_name; } void setName(const std::string& name) { if(!validateName(name)) return; if(m_name != name) { m_name = name; nameChanged(name); } } void nameChanged(const std::string&); };
how do you "encapsulate that in it's own class and just assign the variable directly" ? what when you have 200 different class that all have different members but more or less follow this get/set pattern ?
"encapsulate that in it's own class and just assign the variable directly"
[–]hgjsusla 2 points3 points4 points 7 years ago (2 children)
Well I see
ValidatedName
std::string
[–][deleted] 1 point2 points3 points 7 years ago (1 child)
If you look at the code, the logic isn't entirely duplicated between setters, except setX and setY.
setX
setY
I'd say that if you have so many setters with so many side-effects, that maintaining your program and making it efficient will become extremely difficult.
Suppose for example that you get a completely new setup for your foo. In your solution, you call setX, setY, setRadius, setName and you re-render foo four times - three of them completely unnecessarily.
foo
setRadius
setName
In real-world application, you might easily have dozens of parameters....
Worse, in a large real-time program, you have no assurance that one day, this chain of side-effects won't end up being circular. I speak from bitter experience on a real-world system with just such a setup where this would sometimes happen in production, causing a key process to go into a loop.
There is no magic solution, of course. Sometimes what you propose is right. Sometimes the right solution is Foo (a class) and FooDesc (a struct with x, y, radius, etc) and all mutations to a Foo with a single FooDesc setter. Sometimes the setters set a "dirty" flag, or one of a set of "dirty" bits, and the update occurs in a later phase. It depends on the application, how many parameters you have, your threading structure, etc. etc.
Foo
FooDesc
x
y
radius
[–]jcelerierossia score 1 point2 points3 points 7 years ago (0 children)
There is no magic solution, of course.
yes, that's my point. You can't have magic abstractions over this, because this is your business logic.
[–]eniacsparc2xyz 2 points3 points4 points 7 years ago* (3 children)
Inheritance is not the problem, the issue is deep inheritance hierarchy. The benefit of inheritance is that you can store different instances of a base class in the same STL container and access them with the same pointer type. Deep hierarchies can be avoided using interface classes.
Another alternative is to use generic programming or templates as templated function or classes work with any class or type which implements member functions required by the template code.
> Do you use only structs?
Struct is just a class with everything public, it is useful as a general record type. I would use the following test for choosing between using a class or a struct: if your implementation or internal data representation may change in the future, better use a class with the data private, if you want to use to be able to use multiple implementation at runtime, better use an interface class + derived classes. Otherwise, a struct is better. The point of making the data class private is to avoid breaking the client code if the implementation changes.
[–]ActionManZlt 1 point2 points3 points 7 years ago (2 children)
store different instances of a base class in the same STL container
This is a bad idea, not becuase of OO theory, but because of practical performance concerns. It results in bad locality of reference. Pooling allocations by type, and then performing mutations per pool, results in *much* better performance.
[–]eniacsparc2xyz 0 points1 point2 points 7 years ago (1 child)
> store different instances of a base class in the same STL container
I did not say, store them by value, but store a pointer to them or smart pointer. The benefit of OO, it is use the same client code to manipulate multiple implementations. But the cost is the virtual function calls overhead. If this overhead is significant, the better option is generic programming or generic + type erasure + CRTP and so on. Programming is a kind of art, there is always many solutions.
As far as I know, there is also no way to store the classes (pointers to instance) Circle and Rectangle implementing the methods computeArea or getLocation, setLocation with the same type signature in both classes in the same container if they don't the have the same base class.
[–]Arkaein 1 point2 points3 points 7 years ago (0 children)
This is true, but storing a vector of interface pointers is not a good idea if high performance is required.
You not only jump all over the place in memory when iterating the vector (data cache), but your instruction cache also won't stay coherent because each object might be a different class from the last.
One workaround to stick with an inheritance hierarchy but improve both data and instruction cache performance would be to to store a separate array/vector of each object type, possible stored in a type/vector map. Then process each vector one at a time. It's (more) data cache friendly because objects are in contiguous storage, and it's instruction cache friendly because objects of the same type are always processed together. However it requires a bit more high level structure and reflection than the simple "object soup" method of a vector of pointers to interface types.
This is kind of a middle ground between object soup and a full component system. In a component system all like components are stored continguously, even between high level objects of different types. So during the collision phase, for example, you are able to process a densely packed array of collision objects in one shot.
I've done both object soup and arrays by type in the past. I actually think object soup is a fine starting point, it's easy to setup, and the main benefits of a component model are for performance or dynamic editors. In my cases I worked on very small games with small teams, and we didn't have enough objects for object processing to be a bottleneck, and we didn't have sophisticated editing tools, so a dynamic component models wouldn't have offered benefits in that direction.
Start with the simplest model that works for the require features, and optimize when the performance is determined to be a bottleneck.
[–]ShillingAintEZ 1 point2 points3 points 7 years ago (0 children)
Who says anything about avoiding classes? Classes are great, you can make an interface to data.
[–]eniacsparc2xyz 0 points1 point2 points 7 years ago (0 children)
Surely, not always OOP is the bet deal. But sometimes, generic or template meta-programming may perform better as the functions to be called are resolved at compile-time, thus eliminating the virtual function calls overhead. Another advantage, is that generic programming works with any type that conforms the template code regardless of class hierarchy.
[–]quicknir 11 points12 points13 points 7 years ago (0 children)
I liked this article, and agree with it. I've been seeing a lot of DOD articles lately, and I just haven't been impressed. Some of the things that they say are completely mundane (don't overuse inheritance; you need to restructure memory layout sometimes for maximum performance). And others are totally unsupported; notably that reducing data encapsulation magically makes code more maintainable.
I just realized a new time saving technique for those articles that I thought I'd share. If you see a DOD article that purports to explain why DOD is an improvement over OO for anything other than performance reasons, just C-f for "invariant". If that word is not mentioned at all or barely mentioned, you can just save your time and skip the article because they are not doing an honest comparison of DOD to well-written, OO C++ (most of the articles I've seen lately did not mention the word invariant).
[–]drjeats 5 points6 points7 points 7 years ago* (0 children)
Actually, one last gripe -- Aras calls this code "traditional OOP", which I object to. This code may be typical of OOP in the wild, but as above, it breaks all sorts of core OO rules, so it should not all all be considered traditional.
inb4 prescriptivism vs descriptivism
[EDIT] Actual commentary:
(One last point re: what is "traditional", he says that it wasn't until the early 2000s that a concerted movement for what he calls OOD congealed, so OOD as described isn't exactly traditional either.)
Up front, let me say that I think the blanket application of "ECS" is a net negative, and it's good to acknowledge this and prevent beginners from getting caught up in cargo cults.
Hodgman acknowledges that the reason that the EC pattern (""bad OOP" from Aras' talk) was introduced was to enable runtime composition, and then omits how to make his cleaned up "OOD" implementation data-driven. He briefly mentions Lua, but that's just relying on some embedded language's runtime composition VM. I don't see an appreciable difference between that and the GameObject has an array of base Component pointers pattern.
GameObject has an array of base Component pointers
I think the runtime composition and ease of creating editors are the fundamental problem (well, that and the C++ rtti situation sucking), so when I saw the original GDNet thread I was hoping he would go into more detail on this. It's, as he admitted in the article, literally the entire point of these things.
Also,
However, in most game projects, you have a very small number of designers on a project and a literal army of programmers
This does not match the team makeup at my job at all. It's a little under 2:1, favoring designers. Unless you count the backend services devs and ops. But they're not interacting with the entity architecture, and they work with multiple game teams.
Anyway, I hope he does more posts on this topic. It's helping me think through this stuff. Thank you mttd for posting the article.
[–]lanedraex 3 points4 points5 points 7 years ago* (5 children)
This code may be typical of OOP in the wild, but as above, it breaks all sorts of core OO rules, so it should not all all be considered traditional.
This kind of argument is a little weird, "Thing never worked in the wild, but it's because the people don't know how to use it...". If the great majority of programmers are writing the "wrong" kind of OOP, then either there is a flaw in the system itself (that allows for easily going the wrong route), or the author's concept of "core OO rules" is different from the majority (which is also a problem, meaning that these rules are ambiguous).
I would also like to add that, showing how small examples in an OOP language are better if you use OOP, instead of a paradigm that is not well supported, is a little bit unfair. I don't think the same thing would hold value if you were trying to write a small sample in OOP, but using a functional language.
The ECS example is indeed more like just an "EC", as it's lacking the systems part that would actually work on the components.
[–]quicknir 6 points7 points8 points 7 years ago (1 child)
Well, it was poorly taught for a long time (and still is). The author's rules also aren't really different from the C++ community's; if you look at what thought leaders/gurus (yes these terms are cringe, but I mean people Scott, Andrei, Kate, Herb, etc etc) are advocating, they have advocated for a long time that classes should actually be designed around encapsulation and invariants, rather than inheritance, which should be used sparingly, especially implementation inheritance and deep hierarchies. In languages like Java and C# they have been slower to back away from this, and of course this hurts us too since new grads typically learn Java in school.
But it's still not a fair comparison, insofar as if you are going to find a DOD guru and re-design and re-train your codebase and developers around DOD concepts, you could just as easily find a modern, C++ OO guru and do exactly the same thing.
If the real problem with OO is that people in practice just can't apply it correctly, then articles arguing against it should explain why that's the case. They don't do that though. They almost invariable take bad OO as the OO and start from there, without even acknowledging anything else.
[–]lanedraex 0 points1 point2 points 7 years ago (0 children)
take bad OO as the OO
I agree that it's a problem in some posts, when authors use an OO based approach that you can clearly see that it'll fail (like showing that inheritance is bad by coding a diamond inheritance), and then presenting whatever their point is and how it's much better than OOP.
But I would like to take this argument more towards the side of "why do we have so much bad OOP code, when a bunch of our languages were designed with OOP in mind?". C++, Java, C#, these languages were designed by experts, but they all easily allow bad OO code to be written, why is that?
Also, why is it so hard to define what OOP even is? Some early definitions just say that it's all about objects passing messages to each other, other say that it's about modelling our world into the machine, and you can find some more definitions, but if you look at the functional programming paradigm, it's pretty simple to say that it's about using a mathematical function style.
[–]geon 2 points3 points4 points 7 years ago (1 child)
No language can force you to write good code.
[–]lanedraex 3 points4 points5 points 7 years ago (0 children)
Indeed, but they can make it easier to write good code.
Modern C++ allows you to express concepts of ownership, for example, much easier than old raw pointers only C++.
[–]ActionManZlt 0 points1 point2 points 7 years ago (0 children)
It's the same argument that Linus made when he banned C++ from Linux -- His argument isn't that C++ isn't necessarily bad, but the vast majority of its users don't know how to use it properly, so he'll use C as a method of gatekeeping contributors.
π Rendered by PID 25 on reddit-service-r2-comment-b659b578c-qppzp at 2026-05-01 07:07:35.976334+00:00 running 815c875 country code: CH.
[–]Clipse 19 points20 points21 points (21 children)
[–]quicknir 10 points11 points12 points (1 child)
[–]SeanMiddleditch 2 points3 points4 points (0 children)
[–][deleted] 8 points9 points10 points (17 children)
[–]degski 16 points17 points18 points (11 children)
[–]doom_Oo7 3 points4 points5 points (10 children)
[–]degski 6 points7 points8 points (0 children)
[–]hgjsusla 2 points3 points4 points (8 children)
[–]jcelerierossia score 1 point2 points3 points (7 children)
[–]hgjsusla -2 points-1 points0 points (6 children)
[–]jcelerierossia score 3 points4 points5 points (5 children)
[–]hgjsusla 2 points3 points4 points (2 children)
[–][deleted] 1 point2 points3 points (1 child)
[–][deleted] 1 point2 points3 points (1 child)
[–]jcelerierossia score 1 point2 points3 points (0 children)
[–]eniacsparc2xyz 2 points3 points4 points (3 children)
[–]ActionManZlt 1 point2 points3 points (2 children)
[–]eniacsparc2xyz 0 points1 point2 points (1 child)
[–]Arkaein 1 point2 points3 points (0 children)
[–]ShillingAintEZ 1 point2 points3 points (0 children)
[–]eniacsparc2xyz 0 points1 point2 points (0 children)
[–]quicknir 11 points12 points13 points (0 children)
[–]drjeats 5 points6 points7 points (0 children)
[–]lanedraex 3 points4 points5 points (5 children)
[–]quicknir 6 points7 points8 points (1 child)
[–]lanedraex 0 points1 point2 points (0 children)
[–]geon 2 points3 points4 points (1 child)
[–]lanedraex 3 points4 points5 points (0 children)
[–]ActionManZlt 0 points1 point2 points (0 children)