@@Levelworm No ONLY. You can have any function and any data(int, float, char,...) in your class but if you have at least ONE pure virtual f then that class is kind a interface(you cant Instantiate it).
I’m an Android developer but whenever I want to take a break, I watch a few videos of this c++ series. It is helping me deepen my knowledge of programming.
I viewed this video five months ago but couldn't grasp its meaning until recently when I faced difficulty understanding senior-level code at my workplace. After struggling with comprehending their code, I revisited your video, and everything became clear. Thank you very much! I recommend every junior developer to examine others' code; it helps in understanding the intricacies of features in C++ and when and why to utilize them. Happy coding to all!
This one was a little fast for me, but so far I am loving the series! getting done about 1-2 Videos a day with practice and tasks I set myself. Thank you for creating the best programming tutorial I've found on the Internet thus far!
Thank you for this series. I'm a PLC programmer by trade but I started traditional programming out of pure interest. I came across Interfaces in TwinCAT structured text and could not figure out why they were useful. Thanks to this video I FINALLY understand that they are simply a contract between classes (Function Blocks and methods in TwinCAT). Thank you again!
In 2019 when i first found the channel i quit learning cpp because it was very hard for me to understand thr concepts behind it now its 2021 I learnt java and am pretty good at it... Now im re-watching this playlist and everything is making more sense to me. My advice to very beginner programmers is to get good at easier languages like python, js, and eventually work your way down to c++ then everything will make much more sense....
@@Laevatei1nn i tried to learn cpp in 2018, quit, went back to learning it again at 2020, quit, back to cpp in 2022 but this time i understand it idk why lmaoo
Hey Cherno, love this series. I'm learning a lot. Thank you just got lost on the last two videos about virtual functions, lol. I hope it get clear later on
Because some have asked why pointers were used: you have to use pointers in C++ in order to get polymorphism. Try doing it without pointers and even with the virtual keyword you will not get polymorphism / dynamic dispatch.
First of all, Thank you, for such great cpp series. I think, passing interface to function and using it, is the best usecase of interface as it allow us to have standard logic irrespective of what type of object passed as argument.
He completely convoluted the topic. Interface are very simple. You just declare a class with pure virtual methods[use virtual keyword and "=0" at the end of function], and then inherit that class/interface, and implement that method.
It's late, but If you are new to c++, I recomend watching thenewboston's playlist on c++, then coming back and watching these. They elaborate on the topic very well.
The deeper I get into learning C++... the more difficult it becomes to wrap my head around things. This really started to hit me with the Constructors/Destructors videos by you... I will keep looking into it tho!
@@ytzzn I'll be honest, I watched several more tutorials, even repeated a few chapters.. I kinda gave up. I switched to the Godot engine and that has been a blast.
@sepehrariaei8123 you have to stop watching these, go and just write like 30 programs in C++ using only the knowledge you have now, and then come back to watch these videos again. Also, these last two videos have been in a poor position in the playlist. Skip these two for now and come back later.
I have no idea why some people was talking about interfaces and abstract classes in comments, but the difference is just sematics. We, who write code, defined these to recognize what they represent. For example, `Entity` is an abstract class, it's the base of all entities in the game; and in the other hand, `PrintableInterface`, which defined some traits that a printable object should have, is an interface.
These tutorials have been great so far, but this one gave my brain a run for its money. I was able to piece things together, but this would have been suited for a bit of a slower video in my opinion.
A pure virtual function serves as a declaration (it also imposes a requirement on derived classes to provide their own implementation). This declaration is needed when assigning a pointer of a base class type (by base, I'm referring to the abstract class - the class that provides the pure virtual function) to an object of a derived class type and subsequently calling the function. Without a pure virtual function (or just a virtual function if you want to implement the function inside the base class), the base pointer lacks awareness of any of the function's implementation in derived classes. Not every derived class needs to explicitly implement the function. Instead, if a derived class lacks an implementation, the program will search through the inheritance hierarchy to find one, starting from the current derived class and progressing back to the base class. Only if no implementation is found throughout the hierarchy does it result in a compile-time error.
Thanks again for the series. A bit of critique on this particular episode: while you're talking and editing you're bouncing between lines rather rapidly and it gets confusing occasionally. If you could be a bit more deliberate in the editor, I think it would help clarify things..
Dang, this has gotten way over my head 😂. But will continue to keep watching more and more videos out there. Picking up little by little each time I go through videos and books. One day I'll get it all pieces together.
All the information you are giving us is already available on the internet so It would be nice for the "not beginners" to get also a good tutorial on complex stuff such as streams, memory management and whatever you think is more advance. Awesome Tutorials!
After reading "Introducing Go", i feel like the better example would be about class 'shape' and it's derivatives; also we want to write a function for all shape's derivatives. #include #include class Shape { public: virtual double Area() = 0; virtual double Circum() = 0; }; class Circle : public Shape { public: float x, y, r; public: Circle(float X, float Y, float R) : x(X), y(Y), r(R) {} double Area() override { return 3.14 * r * r; } double Circum() override { return 2 * 3.14 * r; } }; class Rectangle : public Shape { public: float x, y, s; public: Rectangle(float X, float Y, float S) : x(X), y(Y), s(S) {} double Area() override { return s * s; } double Circum() override { return 4 * s; } }; void PrintShapes(std::vector shapes) { for (Shape* shape : shapes) { std::cout
I had to change the speed of this video on slower, because I couldn't keep up :D However, I have to admit that I found out your voice and style of speaking pretty enjoyable! So grateful for your passion and knowledge which you pass on
Dude.. i am loving the series but this one was entirely too fast.. i had to break out the book to get this point. I do however appreciate you for doing this series.
I might recommend to discuss this in terms of the PImpl or Pointer to an Implementation design pattern (see Design Patterns / Gang of 4 book) with a simple class diagram on paper. Then showing how each concrete implementation class that inherits from the interface implement (is forced to) implement the interface. Also another syntax for forcing the user to inherit vs instantiate is to make the interface class constructor and deconstruct member functions protected or private and is just one more indicator to the user that ... yeah you can't instantiate the interface.
Using(Printable obj) makes a copy of that object which can be memory expensive. Thats why (Printable *obj) is a better option since it now points to already existing memory , you could also use (Printable &obj), a reference to Printable obj :D
difference is that first one is pointer and second is instance. we can't create instance from abstract class, but pointer we can and exactly this is a powerful tool
you‘re all missing the most important point: object slicing. In C++ you have to be super careful with polymorphism, it requires a pointer or a reference. Otherwise the copy constructor gets called and slices your subclass
you're not setting anything to zero, it's just a part of c++ syntax. if you'll get used to it, you'll be able to read c++ code like shown in this video with ease.
Because it is old language and I think the concept of interface wasn't really clarified at that moment. I don't know if it's in new C++ releases though, if not, then maybe it's for backwards compatibility reasons.
Well, you COULD if you want to define interface yourself with "#define interface struct" and everytime you write interface it will become a struct (class with public variables as standard). As a new-ish person to C++ I have no idea if this would have SOME kind of negative income, but I tried it out and it works. I'd guess maby compiling-time increases **slightly** but meh. /shrug
+valrossenOliver, yes, "#define interface struct" is generally a bad idea, because c-style macros are dangerous, obscuring, and hard to debug. there's tons and tons of articles about how bad it can get when a person uses too many #define macros, look it up. compiling time will not be affected at all (well, actually, preprocessor will have to do more work substituting every occurrence of "interface" to "struct" in your code).
Why the GetClassName() method in the Entity class isn't virtual? yet we are still able to override it in the Player class. Does that mean we only need the mother method to be virtual?
Different implementations of Java Sets for example (HashSet, LinkedHashSet,...) that all have to have some functionality. This functionality is guaranteed by implementing a common interface
I have just had the need to make an interface for the first time ever (when I learned about them I used them but I didn't see why I would use them in those situations, it just seemed unnecessary. I never had a situation where writing my own interface seemed necessary or convenient. I had implemented interfaces that already existed in libraries such as awt and swing and I saw value in those interfaces but I have never had the need to write my own interfaces until now). I was dealing with a Mongo database. I wanted to make a method which will change id of collection members in the database. I want every object in the database to have a unique identification number, I called it pid. So, my method takes as an argument an object which has a pid field and then changes it. How would you write that? How would you tell the compiler that this method receives an object which has a field called pid? By having the method take an instance of the interface as the argument. Interface has getPid and setPid methods. If you don't do that, you will have to write separate methods for every single class that you want to put in your database. I wrote this in Java and I used generics (if you were to do this in C++ you would use templates, they are similar to generics in Java).
Another example where you can write your own interface is if you write your own Event Object. Event Objects hold references to bunch of objects. Those objects are called event listeners. When some event happens the event object activates a certain method of its event listeners. That's why they are called event listeners, they will be "told" when an event happens, because the event object will activate their method. We would like objects of various classes to be event listeners, so we use an interface. For instance, interface has a method itIs7Am() and all object listeners implement that interface. If you have a class employee, they implement it by going to a job, class student implements it by going to university, class Bird implements it by starting to sing. Event object will activate the method itIs7Am of all of its listeners even though its listeners belong to various different classes and they implement this method in very different ways. Examples for when you use an interface which was already written can also be event listeners, like ActionListener interface in Java awt library which is used a lot. When button is pressed, it activates action Performed method of all of its listeners. All of its listeners have the method actionPerformed because they implement interface ActionListener, even though they implement the method actionPerformed in various different ways.
The method that I wrote goes like this public void changeId(MongoCollection mgCollection, int pidIncrease){ for(T object : mgCollection.find()){ int pid = Integer.parseInt(object.getPid()); int newPid = pid + pidIncrease; Bson QUERY = Filters.eq("pid", String.valueOf(pid)); Bson UPDATE = Updates.set("pid", String.valueOf(newPid)); mgCollection.updateOne(QUERY, UPDATE); } } I am going through collection and changing pid of members. This method will work for collection of any objects in the database, because I only have collection of objects which implement PidInterface and I have getPid method in the PidInterface. I can have objects of various different classes in the database but they all need to implement PidInterface so that I can do operations on them. As you can see, the method which does operation on those objects in the database (changes their pid in this case) receives a MongoCollection which is made out of objects that implement the PidInterface. If I don't use an interface I would have to write a separate method for each class whose instances are in the database.
Why not using structs as interfaces? They have default public visibility so they would looklike interfaces in other programming languages such as Java or C# and you would also remove the verbosity of setting public visibility for all the interface's methods.
hey, cherno! what do you think of creating quizzes and assignments and making it a full blown course? i know i would pay for such a course, and im sure large companies would really value the qualifications that you endow upon people!
It would be nice if you do "interface" again, and explain vptr(Virtual Pointer) vtbl(Virtual Table), and that size of object increase by 4|8 bytes (depends on architecture), due to VTPR. Thank you in advance.
How do you destruct Printable (assuming that GetClassName actually had destructable arguments)? Would you need a pure virtual destructor or would a regular virtual destructor work?
Love the series, working my way through. Question: How can I make sure that 'Player' provides its own implementation of the pure virtual function? You showed that if it doesn't, it ends up using the version inherited from 'Entity', but I want to force all child classes to provide their own implementation. Thanks for the video series, really enjoying it.
Let’s say “Entity” has a function named “getAge” that returns an int. “Entity” can either have its own version of the function, or be 'pure' (but not both). for example: version with implementation: virtual int getAge( ) { return 10; } OR “Pure” version: virtual int getAge() = 0; If “ENTITY” declares implementation, then sub-classes (like “Player”) can optionally override or just ignore it. But if “ENTITY” declares as “pure” (virtual int getAge() = 0;) then sub-classes (like “Player”) have the obligation to provide an implementation for themselves.
First. C++ is stupid as heck when it comes to abstract/pure classes. TL;DR create base class, define constructor and virtual destructor as empty `base() {} virtual ~base() {}` (or just leave a default constructor who cares) Then create the pure functions as virtual without a body `{}` and it will fail to compile when you make a class `void pure(int _unused);` However. C++ is AWFUL at doing inheritance and the error messages are terrible. And you can easily "shadow" or "override" virtual function names with no error. It's particularly bad if you make a mistake. To mitigate it you have a few options - Pure specifier. `virtual void pure(int _unused) = 0` the =0 part is the pure specified and will give an error message if it's unimplimented. - Error messages (mainly just clang) `-Werror=overloaded-virtual` will cause a compile error - Override attribute. Tell the compiler you *intend* to override a virtual function and it will error if the definition differs. This is easily one of my least favourite parts of C++ the fact you have to do it at all is madness. It relies on the writer being smart. `void overriden_pure(int _unused) override {}`
3:58 > _"i keep calling interface - it's just a class in cpp, unlike othe langs which provide a keyw for it"_ ohkayyy, ohkay. thanks a lot, i was kinda unable to really understand what interface in other langs (kotlin) were. i will give it a second go now after watching this.
Hardcore Tutorial, this was confusing. I think you really set a standard in explaining code with your series but the last two ones...uff...I got it but it really wasn't easy to grasp. Thanks for explaining but those last Tutorials lacked the easy comprehensabilty. I think it was due to the overloaded cpp-Project. Still grateful.
You explained things crystal clear. However, the examples like Entity class are probably the worst you could choose from. A sub type is always a *more specific* type of the base/parent type. If you could use examples like Animals, Fruits, Shapes, that would be much better.
Still, it's a good example, he was talking about entities which are part of a computer game.He kept that relation between a parent class and a child class, the child has to be a "sub-type" of the parent class.He could go on to enforce this relation by providing the general examples you have provided.One important thing to remember, don't go on and use inheritance all over the place, use it when you encounter things that derives from other things.
Lot of questions left unanswered I felt. Why was Printable turned into a pointer in the function argument? lot of scrolling which left me confusing ://
Would I be correct to say that pure virtual functions could be very useful for cross-platform code (eg Mac or Windows), where one base class can be called, which leads to sub-classes which have code that correspond to the particular platform being used in the compiler? So the main code can be universal, but the sub-class code can be platform-specific, eg a 'Mac' class, or a 'Windows' class - depending on which platform you were looking to compile at the time. If this is the case, would a 'flag' be set at the start of the program so the correct class (Mac class or Windows class) would be used throughout the program wherever necessary?
That's actually one of the worst cases to use virtual functions/interfaces or even inheritance IMHO because the code for Windows typically won't build on Mac and vice versa. So even if you make a subtype for Windows and a subtype for Mac of a particular virtual interface, you'll still have to rely on the preprocessor or the build system to filter out all implementation code except the one for the platform being built against, and at that point virtual/dynamic dispatch becomes useless since there's no varying runtime condition/input to use to select which function to call. All that can and should be resolved at compile time. For cross-platform code, it's often much simpler to just use a concrete class, possibly with a pimpl, like so: // Gui.h #pragma once class Gui { public: ... private: class Impl; std::unique_ptr pimpl; }; Then you might have like a 'GuiWindows.cpp' for Windows, 'GuiOsx.cpp' for OSX, maybe one or more for Linux, and have your build system include the right source file(s) based on the platform. Or you might just have a large 'Gui.cpp' with a bunch of #ifdefs/#ifndefs based on the platform we're targeting. The branching occurs at compile-time, so to speak, rather than runtime. It makes no sense to branch at runtime here. This is a job for your preprocessor or your build system, so to speak, not virtual dispatch. Of course, the virtual dispatch might be useful for event-handling or something. You might still put some virtual functions in the Gui class above and allow people to inherit the base class and override those functions. But it makes no practical sense to me to be using virtual dispatch based on the runtime condition of what operating system/platform is being used... at least until operating systems establish enough of a standard that code designed for other operating systems build on a particular system and we have cross-platform binaries (ex: a single binary executable that can be executed on Windows, OSX, and Linux without requiring separate binaries for each target). An example that's still close but where virtual dispatch might be suitable is to select an underlying rendering target. For example, you might create a virtual interface for rendering which abstracts both the capabilities of OpenGL and DirectX in a single abstract interface, then implement one subtype for OpenGL and another for DirectX. That makes more sense because if the user is running Windows, they have both available and might be able to change which one to use at runtime by changing preferences or a config file. In any case, you should generally reserve the use of virtual dispatch for cases where the actual overridden function that is called is based on a runtime condition/user input. Otherwise, it's just a needless overhead both for the programmer (virtual interfaces and ABCs tend to be more clunky to use) and CPU if the actual functions to call can be resolved at compile-time. If this seems a bit confusing just think about where if/else is appropriate first. Would it make sense to write code like this? if (os == windows) { ... } else if (os == osx) { ... } else if (os == linux) { ... } No, right? Typically you'd need to use the preprocessor here to write code that even builds, and the operating system we're using is not a variable that can be changed at runtime. In those cases, virtual dispatch makes little sense. Meanwhile using if/else for render target might make sense: if (render_target == directx) { ... } else if (render_target == opengl) { ... } And likewise, virtual dispatch makes sense as an alternative to the if/else here.
I see you use =0 to force an implementation of a method which returns a value. But what about a method that is perhaps "void the_method(int x)". How do you force an implementation of this? Do you put =0 at the end? Doesn't make sense really since the method doesn't return anythingn.
Hi Yan! I've 2 questions : 1/ in C++ is there a difference between Interface and Abstract class like in Java for example? 2/ at 5:40 You said Print(new A()); is a memory leak, could you explain a bit? Thank you
In Java the difference between Abstract classes and interfaces is pretty much it : Methods of a Java interface are implicitly abstract and cannot have implementations (pure virtual). A Java abstract class can have instance methods that implements a default behavior.
For people who didn't understand a thing: Pure virtual functions are declared in a parent class, but can't be neither defined nor be instantiated from that class. If you want to use that method, you would have to redeclare and redefine it in a child class. Only then it can be used and instantiated. So basically it's just a blueprint of a function which can be derived by a child class from a parent class.
Also, assuming I understood correctly; if a child's (parent class) inherits an interface, the child class will also be able to implement the interface's methods without having to inherit the interface as well.
Am I right that, in the last example if I create Entity e = new Player(); and call e.GetClassName() it will get me "Entity" and not "Player"? And in order to get "Player", the GetClassName() function in Entity should be virtual as well?
I don't think these videos are for beginners. But since I have some background in programming and C++, I found them very helpful.
@@elonmusk7283 From my understanding an Interface is just a special kind of class that consists of virtual functions ONLY.
@@Levelworm No ONLY. You can have any function and any data(int, float, char,...) in your class but if you have at least ONE pure virtual f then that class is kind a interface(you cant Instantiate
it).
@@aleksandarfranc1094 You are right! I need to brush up my C++...
@Aleksandar Franc I'd actually call that an abstract class not an interface...
@@martinprochazka3714 It behaves as an interface, but that makes it an abstract class
I’m an Android developer but whenever I want to take a break, I watch a few videos of this c++ series. It is helping me deepen my knowledge of programming.
dude you need a hobby. it is like having a knife and try to cut yourself here and there.
This video just overrode the thinking method of my brain class.
And it set the body to 'return "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"''
@@ezshroom why?
I'm sure the thinking method of your brain class is pure virtual and a subclass has it returning: "Im strange."
@@smileynetsmileynet7922 I am very cool and exemplary. Almost like Jesus.
is 'thinking' a pure method? what i mean by that is that 'thinking' is equal to zero.
I viewed this video five months ago but couldn't grasp its meaning until recently when I faced difficulty understanding senior-level code at my workplace. After struggling with comprehending their code, I revisited your video, and everything became clear. Thank you very much! I recommend every junior developer to examine others' code; it helps in understanding the intricacies of features in C++ and when and why to utilize them. Happy coding to all!
clears a whole lot of uncertainties I don't even know I have deeply in my mind, simple and straight forward. GJ!
This one was a little fast for me, but so far I am loving the series! getting done about 1-2 Videos a day with practice and tasks I set myself. Thank you for creating the best programming tutorial I've found on the Internet thus far!
Thank you for this series. I'm a PLC programmer by trade but I started traditional programming out of pure interest. I came across Interfaces in TwinCAT structured text and could not figure out why they were useful. Thanks to this video I FINALLY understand that they are simply a contract between classes (Function Blocks and methods in TwinCAT). Thank you again!
I *LOVE* the clarity of explanation in your videos.
one of my fav series these days on youtube
In 2019 when i first found the channel i quit learning cpp because it was very hard for me to understand thr concepts behind it now its 2021 I learnt java and am pretty good at it... Now im re-watching this playlist and everything is making more sense to me. My advice to very beginner programmers is to get good at easier languages like python, js, and eventually work your way down to c++ then everything will make much more sense....
tried to learn cpp in 2020, quit, learn python, quit, back to cpp in 2021 and actually understand the concepts idk why lmfao
@@Laevatei1nn i tried to learn cpp in 2018, quit, went back to learning it again at 2020, quit, back to cpp in 2022 but this time i understand it idk why lmaoo
@@xarkiwillprevail same, i went to college this year and learning this definitely pays off
Hey Cherno, love this series. I'm learning a lot. Thank you
just got lost on the last two videos about virtual functions, lol. I hope it get clear later on
same man exact same
You got it clear now?
the same feeling
It's too rare that I don't need to set the video playback 1.25x or 1.5x
watch dark docs videos and you won't ever say that again.
@@TheSiprianus Haha. Not only his voice... but the whole video seems speed up to 1.5x speed.
Because some have asked why pointers were used: you have to use pointers in C++ in order to get polymorphism. Try doing it without pointers and even with the virtual keyword you will not get polymorphism / dynamic dispatch.
Very good episode, I always struggled with this and now feel ashamed because it's so dead simple, thanks to the brilliant explanation.
I don’t know if you still check comments here, but thank you for carrying me through 3rd year engineering. My profs suck and you’re a life saver
First of all, Thank you, for such great cpp series.
I think, passing interface to function and using it, is the best usecase of interface as it allow us to have standard logic irrespective of what type of object passed as argument.
This was the first video where i didnt understand a single thing.
He completely convoluted the topic. Interface are very simple. You just declare a class with pure virtual methods[use virtual keyword and "=0" at the end of function], and then inherit that class/interface, and implement that method.
@@heksogen4788 you just saved me 6mins...
It's late, but If you are new to c++, I recomend watching thenewboston's playlist on c++, then coming back and watching these. They elaborate on the topic very well.
right,except =0 to make it pure
@@heksogen4788 still don't get it! why would i use this? i know the usage of virtual keyword but i don't know to why we use the pure virtual!
The deeper I get into learning C++... the more difficult it becomes to wrap my head around things. This really started to hit me with the Constructors/Destructors videos by you...
I will keep looking into it tho!
Did you finish the series and did you understand?
because I'm currently at this episode 28/100 and I'm starting to not understand.
@@ytzzn I'll be honest, I watched several more tutorials, even repeated a few chapters.. I kinda gave up.
I switched to the Godot engine and that has been a blast.
@@Special4ce293 Alr ty
me too. I am not catching up anymore from constructures
@sepehrariaei8123 you have to stop watching these, go and just write like 30 programs in C++ using only the knowledge you have now, and then come back to watch these videos again. Also, these last two videos have been in a poor position in the playlist. Skip these two for now and come back later.
I have no idea why some people was talking about interfaces and abstract classes in comments, but the difference is just sematics. We, who write code, defined these to recognize what they represent.
For example, `Entity` is an abstract class, it's the base of all entities in the game; and in the other hand, `PrintableInterface`, which defined some traits that a printable object should have, is an interface.
Dude, thanks for these short but to the point videos! I liked the examples too.
These tutorials have been great so far, but this one gave my brain a run for its money. I was able to piece things together, but this would have been suited for a bit of a slower video in my opinion.
A pure virtual function serves as a declaration (it also imposes a requirement on derived classes to provide their own implementation). This declaration is needed when assigning a pointer of a base class type (by base, I'm referring to the abstract class - the class that provides the pure virtual function) to an object of a derived class type and subsequently calling the function. Without a pure virtual function (or just a virtual function if you want to implement the function inside the base class), the base pointer lacks awareness of any of the function's implementation in derived classes. Not every derived class needs to explicitly implement the function. Instead, if a derived class lacks an implementation, the program will search through the inheritance hierarchy to find one, starting from the current derived class and progressing back to the base class. Only if no implementation is found throughout the hierarchy does it result in a compile-time error.
Thanks again for the series. A bit of critique on this particular episode: while you're talking and editing you're bouncing between lines rather rapidly and it gets confusing occasionally. If you could be a bit more deliberate in the editor, I think it would help clarify things..
I've got cpp exam in 2 days and I came for const function but you also answered my questions about mutable, Love you man
Dang, this has gotten way over my head 😂. But will continue to keep watching more and more videos out there. Picking up little by little each time I go through videos and books. One day I'll get it all pieces together.
Can you make a video about memory leaks?
Yes
NICEEEEEEE!!!!!
TheChernoProject You should do that next if you don't have another video planned. It seems really interesting!
All the information you are giving us is already available on the internet so It would be nice for the "not beginners" to get also a good tutorial on complex stuff such as streams, memory management and whatever you think is more advance.
Awesome Tutorials!
i was just going to ask him
After reading "Introducing Go", i feel like the better example would be about class 'shape' and it's derivatives; also we want to write a function for all shape's derivatives.
#include
#include
class Shape {
public:
virtual double Area() = 0;
virtual double Circum() = 0;
};
class Circle : public Shape {
public:
float x, y, r;
public:
Circle(float X, float Y, float R) : x(X), y(Y), r(R) {}
double Area() override {
return 3.14 * r * r;
}
double Circum() override {
return 2 * 3.14 * r;
}
};
class Rectangle : public Shape {
public:
float x, y, s;
public:
Rectangle(float X, float Y, float S) : x(X), y(Y), s(S) {}
double Area() override {
return s * s;
}
double Circum() override {
return 4 * s;
}
};
void PrintShapes(std::vector shapes) {
for (Shape* shape : shapes) {
std::cout
Thank you so much for this example. You won't believe how much it helped dude, now I get why interfaces are useful! Your amazing!!
We're getting to the interesting stuff now
Thank for the quick explanation!
Bro you are flying over these topics!! But i am still following you! You are challenging us and put us in uncomfort zone! I like it! Thanks!
for the first time in my life, i played a video at .75X, my brain cells have been ashamed .
I had to change the speed of this video on slower, because I couldn't keep up :D However, I have to admit that I found out your voice and style of speaking pretty enjoyable! So grateful for your passion and knowledge which you pass on
Good episode. Looking forward to many of the vids coming up.
Much love, brother
Thanks a lot for your c++ series.
Thank you very much for making these amazing tutorials!!!
This video wass sooo good ( as always haha )! Thank you Cherno!
Dude.. i am loving the series but this one was entirely too fast.. i had to break out the book to get this point. I do however appreciate you for doing this series.
So, in short, can we say for pure visual functions that we just declare the function in the base class and give definitions in the sub-classes?
I might recommend to discuss this in terms of the PImpl or Pointer to an Implementation design pattern (see Design Patterns / Gang of 4 book) with a simple class diagram on paper. Then showing how each concrete implementation class that inherits from the interface implement (is forced to) implement the interface. Also another syntax for forcing the user to inherit vs instantiate is to make the interface class constructor and deconstruct member functions protected or private and is just one more indicator to the user that ... yeah you can't instantiate the interface.
Why did You use (Printable* obj) instead of just (Printable obj)? Whats the difference?
Using(Printable obj) makes a copy of that object which can be memory expensive. Thats why (Printable *obj) is a better option since it now points to already existing memory , you could also use (Printable &obj), a reference to Printable obj :D
Mateo G Thank you for explanation =)
difference is that first one is pointer and second is instance. we can't create instance from abstract class, but pointer we can and exactly this is a powerful tool
you‘re all missing the most important point: object slicing. In C++ you have to be super careful with polymorphism, it requires a pointer or a reference. Otherwise the copy constructor gets called and slices your subclass
Why doesn't C++ have some sort of interface keyword like other languages do? It doesn't make much sense that you have to set the function to zero.
you're not setting anything to zero, it's just a part of c++ syntax. if you'll get used to it, you'll be able to read c++ code like shown in this video with ease.
Because it is old language and I think the concept of interface wasn't really clarified at that moment. I don't know if it's in new C++ releases though, if not, then maybe it's for backwards compatibility reasons.
Well, you COULD if you want to define interface yourself with "#define interface struct" and everytime you write interface it will become a struct (class with public variables as standard).
As a new-ish person to C++ I have no idea if this would have SOME kind of negative income, but I tried it out and it works. I'd guess maby compiling-time increases **slightly** but meh. /shrug
RadiationAlert N/A Doing it like this allows you to define some methods in the "interface" by not adding an "=0" at the end of some functions.
+valrossenOliver, yes, "#define interface struct" is generally a bad idea, because c-style macros are dangerous, obscuring, and hard to debug. there's tons and tons of articles about how bad it can get when a person uses too many #define macros, look it up. compiling time will not be affected at all (well, actually, preprocessor will have to do more work substituting every occurrence of "interface" to "struct" in your code).
I really like your videos cherno! Keep it up.
gotta keep diggin into it, confusing though. thanks for the videos!
one who never programmed object oriented before cannot understand this at all. Happy I did
These are basically what Traits are in Rust. Pretty cool.
Thank you.
4:42 wait, cpp has an override keyword?
Now i'm gonna ace this test.
Fantastic video
Does "pure virtual function" approach have similar overhead as "virtual function"?
it was really helpful ,
thanks
Welcome 🙏
So clear
superb
Why the GetClassName() method in the Entity class isn't virtual? yet we are still able to override it in the Player class. Does that mean we only need the mother method to be virtual?
it is virtual although the keyword isn't there ( you can add it for more clarity).
Pure virtual functions allow us to define a function in a base class which doesn't have an implementation
Thanks man
Thanks
Thanks for this video!
the video is 7 mins but it takes 20 mins to understand
Thought i was crazy
You’re the best
Thanks for your video!
Perfect alternative to tutorialspoint
Could you give a more real world scenario to help wrap my head around this?
Different implementations of Java Sets for example (HashSet, LinkedHashSet,...) that all have to have some functionality. This functionality is guaranteed by implementing a common interface
I have just had the need to make an interface for the first time ever (when I learned about them I used them but I didn't see why I would use them in those situations, it just seemed unnecessary. I never had a situation where writing my own interface seemed necessary or convenient. I had implemented interfaces that already existed in libraries such as awt and swing and I saw value in those interfaces but I have never had the need to write my own interfaces until now). I was dealing with a Mongo database. I wanted to make a method which will change id of collection members in the database. I want every object in the database to have a unique identification number, I called it pid.
So, my method takes as an argument an object which has a pid field and then changes it.
How would you write that? How would you tell the compiler that this method receives an object which has a field called pid?
By having the method take an instance of the interface as the argument. Interface has getPid and setPid methods.
If you don't do that, you will have to write separate methods for every single class that you want to put in your database.
I wrote this in Java and I used generics (if you were to do this in C++ you would use templates, they are similar to generics in Java).
Another example where you can write your own interface is if you write your own Event Object. Event Objects hold references to bunch of objects. Those objects are called event listeners. When some event happens the event object activates a certain method of its event listeners. That's why they are called event listeners, they will be "told" when an event happens, because the event object will activate their method. We would like objects of various classes to be event listeners, so we use an interface. For instance, interface has a method itIs7Am() and all object listeners implement that interface. If you have a class employee, they implement it by going to a job, class student implements it by going to university, class Bird implements it by starting to sing. Event object will activate the method itIs7Am of all of its listeners even though its listeners belong to various different classes and they implement this method in very different ways.
Examples for when you use an interface which was already written can also be event listeners, like ActionListener interface in Java awt library which is used a lot. When button is pressed, it activates action Performed method of all of its listeners. All of its listeners have the method actionPerformed because they implement interface ActionListener, even though they implement the method actionPerformed in various different ways.
The method that I wrote goes like this
public void changeId(MongoCollection mgCollection, int pidIncrease){
for(T object : mgCollection.find()){
int pid = Integer.parseInt(object.getPid());
int newPid = pid + pidIncrease;
Bson QUERY = Filters.eq("pid", String.valueOf(pid));
Bson UPDATE = Updates.set("pid", String.valueOf(newPid));
mgCollection.updateOne(QUERY, UPDATE);
}
}
I am going through collection and changing pid of members. This method will work for collection of any objects in the database, because I only have collection of objects which implement PidInterface and I have getPid method in the PidInterface. I can have objects of various different classes in the database but they all need to implement PidInterface so that I can do operations on them. As you can see, the method which does operation on those objects in the database (changes their pid in this case) receives a MongoCollection which is made out of objects that implement the PidInterface.
If I don't use an interface I would have to write a separate method for each class whose instances are in the database.
This lad is a very intelligent one.
You are the best.
Why not using structs as interfaces? They have default public visibility so they would looklike interfaces in other programming languages such as Java or C# and you would also remove the verbosity of setting public visibility for all the interface's methods.
Matter of style mostly. I like to keep structs for packed data structures, aka POD (Plain Old Data).
.
thanks a lot!
You are amazing !! :-)
Nice. Really well explained :)
hey, cherno! what do you think of creating quizzes and assignments and making it a full blown course? i know i would pay for such a course, and im sure large companies would really value the qualifications that you endow upon people!
hey, could you post a .txt file with you code. It would help to understand the video since you scroll a little bit too fast during the video
It would be nice if you do "interface" again, and explain vptr(Virtual Pointer) vtbl(Virtual Table), and that size of object increase by 4|8 bytes (depends on architecture), due to VTPR.
Thank you in advance.
How do you destruct Printable (assuming that GetClassName actually had destructable arguments)? Would you need a pure virtual destructor or would a regular virtual destructor work?
Love the series, working my way through. Question: How can I make sure that 'Player' provides its own implementation of the pure virtual function? You showed that if it doesn't, it ends up using the version inherited from 'Entity', but I want to force all child classes to provide their own implementation. Thanks for the video series, really enjoying it.
Let’s say “Entity” has a function named “getAge” that returns an int. “Entity” can either have its own version of the function, or be 'pure' (but not both).
for example:
version with implementation:
virtual int getAge( ) {
return 10;
}
OR
“Pure” version:
virtual int getAge() = 0;
If “ENTITY” declares implementation, then sub-classes (like “Player”) can optionally override or just ignore it.
But if “ENTITY” declares as “pure” (virtual int getAge() = 0;) then sub-classes (like “Player”) have the obligation to provide an implementation for themselves.
First.
C++ is stupid as heck when it comes to abstract/pure classes.
TL;DR create base class, define constructor and virtual destructor as empty `base() {} virtual ~base() {}` (or just leave a default constructor who cares)
Then create the pure functions as virtual without a body `{}` and it will fail to compile when you make a class `void pure(int _unused);`
However. C++ is AWFUL at doing inheritance and the error messages are terrible. And you can easily "shadow" or "override" virtual function names with no error. It's particularly bad if you make a mistake. To mitigate it you have a few options
- Pure specifier. `virtual void pure(int _unused) = 0` the =0 part is the pure specified and will give an error message if it's unimplimented.
- Error messages (mainly just clang) `-Werror=overloaded-virtual` will cause a compile error
- Override attribute. Tell the compiler you *intend* to override a virtual function and it will error if the definition differs. This is easily one of my least favourite parts of C++ the fact you have to do it at all is madness. It relies on the writer being smart. `void overriden_pure(int _unused) override {}`
Just awesome
Wait den what's da difference between an interface and an abstract class?
3:58 > _"i keep calling interface - it's just a class in cpp, unlike othe langs which provide a keyw for it"_
ohkayyy, ohkay. thanks a lot, i was kinda unable to really understand what interface in other langs (kotlin) were.
i will give it a second go now after watching this.
can you please make video on design patterns........Please :) thanks lot
Hardcore Tutorial, this was confusing. I think you really set a standard in explaining code with your series but the last two ones...uff...I got it but it really wasn't easy to grasp. Thanks for explaining but those last Tutorials lacked the easy comprehensabilty. I think it was due to the overloaded cpp-Project. Still grateful.
You explained things crystal clear. However, the examples like Entity class are probably the worst you could choose from. A sub type is always a *more specific* type of the base/parent type. If you could use examples like Animals, Fruits, Shapes, that would be much better.
Still, it's a good example, he was talking about entities which are part of a computer game.He kept that relation between a parent class and a child class, the child has to be a "sub-type" of the parent class.He could go on to enforce this relation by providing the general examples you have provided.One important thing to remember, don't go on and use inheritance all over the place, use it when you encounter things that derives from other things.
i lost you after inheritance
while (true){
//Intro template
std::cout
Thanks!!!
So, I guess they are called protocols in Swift
Lot of questions left unanswered I felt. Why was Printable turned into a pointer in the function argument? lot of scrolling which left me confusing ://
Would I be correct to say that pure virtual functions could be very useful for cross-platform code (eg Mac or Windows), where one base class can be called, which leads to sub-classes which have code that correspond to the particular platform being used in the compiler? So the main code can be universal, but the sub-class code can be platform-specific, eg a 'Mac' class, or a 'Windows' class - depending on which platform you were looking to compile at the time.
If this is the case, would a 'flag' be set at the start of the program so the correct class (Mac class or Windows class) would be used throughout the program wherever necessary?
That's actually one of the worst cases to use virtual functions/interfaces or even inheritance IMHO because the code for Windows typically won't build on Mac and vice versa. So even if you make a subtype for Windows and a subtype for Mac of a particular virtual interface, you'll still have to rely on the preprocessor or the build system to filter out all implementation code except the one for the platform being built against, and at that point virtual/dynamic dispatch becomes useless since there's no varying runtime condition/input to use to select which function to call. All that can and should be resolved at compile time.
For cross-platform code, it's often much simpler to just use a concrete class, possibly with a pimpl, like so:
// Gui.h
#pragma once
class Gui
{
public:
...
private:
class Impl;
std::unique_ptr pimpl;
};
Then you might have like a 'GuiWindows.cpp' for Windows, 'GuiOsx.cpp' for OSX, maybe one or more for Linux, and have your build system include the right source file(s) based on the platform. Or you might just have a large 'Gui.cpp' with a bunch of #ifdefs/#ifndefs based on the platform we're targeting. The branching occurs at compile-time, so to speak, rather than runtime. It makes no sense to branch at runtime here. This is a job for your preprocessor or your build system, so to speak, not virtual dispatch.
Of course, the virtual dispatch might be useful for event-handling or something. You might still put some virtual functions in the Gui class above and allow people to inherit the base class and override those functions. But it makes no practical sense to me to be using virtual dispatch based on the runtime condition of what operating system/platform is being used... at least until operating systems establish enough of a standard that code designed for other operating systems build on a particular system and we have cross-platform binaries (ex: a single binary executable that can be executed on Windows, OSX, and Linux without requiring separate binaries for each target).
An example that's still close but where virtual dispatch might be suitable is to select an underlying rendering target. For example, you might create a virtual interface for rendering which abstracts both the capabilities of OpenGL and DirectX in a single abstract interface, then implement one subtype for OpenGL and another for DirectX. That makes more sense because if the user is running Windows, they have both available and might be able to change which one to use at runtime by changing preferences or a config file. In any case, you should generally reserve the use of virtual dispatch for cases where the actual overridden function that is called is based on a runtime condition/user input. Otherwise, it's just a needless overhead both for the programmer (virtual interfaces and ABCs tend to be more clunky to use) and CPU if the actual functions to call can be resolved at compile-time.
If this seems a bit confusing just think about where if/else is appropriate first. Would it make sense to write code like this?
if (os == windows)
{
...
}
else if (os == osx)
{
...
}
else if (os == linux)
{
...
}
No, right? Typically you'd need to use the preprocessor here to write code that even builds, and the operating system we're using is not a variable that can be changed at runtime. In those cases, virtual dispatch makes little sense. Meanwhile using if/else for render target might make sense:
if (render_target == directx)
{
...
}
else if (render_target == opengl)
{
...
}
And likewise, virtual dispatch makes sense as an alternative to the if/else here.
@@darkengine5931 Thanks for the explanation, and thanks for giving an example of when it could be used. I do understand what you said.
Thanks for this video, but it would be nice if you could speak and switch between codes more slowly so that we can analyze what you are teaching...
@ 5:26
I forgot to put public (that means its private).
But still no error.
prints "A" correctly.
But WHY?
How does Print() function call private function of A?
Nice Video!! Very clear explanation.
How do you navigate so fast in code?
magic
Can someone explain why override was used for Entity but not A since they are sort of at the same level of branching
Should have mentioned of a virtual destructor in base class.
Really good)
I see you use =0 to force an implementation of a method which returns a value. But what about a method that is perhaps "void the_method(int x)". How do you force an implementation of this? Do you put =0 at the end? Doesn't make sense really since the method doesn't return anythingn.
Hi Yan! I've 2 questions :
1/ in C++ is there a difference between Interface and Abstract class like in Java for example?
2/ at 5:40 You said Print(new A()); is a memory leak, could you explain a bit?
Thank you
2/ -> Everytime you use the "new" operator for dinamyc memory allocation you also need to free that memory manualy with "delete" or "delete[].
Thank you
In Java the difference between Abstract classes and interfaces is pretty much it : Methods of a Java interface are implicitly abstract and cannot have implementations (pure virtual). A Java abstract class can have instance methods that implements a default behavior.
For people who didn't understand a thing: Pure virtual functions are declared in a parent class, but can't be neither defined nor be instantiated from that class. If you want to use that method, you would have to redeclare and redefine it in a child class. Only then it can be used and instantiated. So basically it's just a blueprint of a function which can be derived by a child class from a parent class.
Cheers for helping ppl but vid is 4 years old, doubt he reads comments that much.
Also, assuming I understood correctly; if a child's (parent class) inherits an interface, the child class will also be able to implement the interface's methods without having to inherit the interface as well.
Can you make a video about Multiple Inheritance?
Am I right that, in the last example if I create Entity e = new Player(); and call e.GetClassName() it will get me "Entity" and not "Player"? And in order to get "Player", the GetClassName() function in Entity should be virtual as well?
Great