Author Topic: Learning C++ from a C# background  (Read 6686 times)

Offline Vagabond

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1013
Learning C++ from a C# background
« on: February 16, 2016, 10:01:04 PM »
So, I've been picking up C++, learning it as I work on a colony map. For context, I've spent a lot of time using C#.

A couple of observations so far:

I really like the ability to set const on function variables. In C#, you typically had to either create a copy of a class instance or trust the user didn't mess with the instance you passed them. I also enjoy using the address of operator (ampersand) on variables since it makes it very clear if you are passing a copy or reference to the original.

I dislike how classes are declared in header files with all their private members. It is awkward to me to spell out so much implementation up front to the user.

It would be nice if the standard library function names were a little more descriptive, but I guess they will come eventually. One of the nice things about the .net framework is how descriptive all the library function names are. Part of this is probably just needing more practice with the standard library. It does feel like the the C++ standard library is much smaller than the .Net library. I wonder if part of this is because the .Net library is designed for windows only where the standard library is used on many platforms and cannot be as specific.

I'm not a fan of random enumeration values littering the namespace. In the Outpost 2 SDK, the namespace has hundreds of enums from different places like map_id, UnitDirection, BeaconType, etc (hundreds might be a bit of an exaggeration). I think this is an age issue though since Outpost 2 was programmed before C++11, which allows for strongly typed enums.

I'm getting close to completing a colony game and will post about it in the near future.

Offline dave_erald

  • Sr. Member
  • ****
  • Posts: 262
Re: Learning C++ from a C# background
« Reply #1 on: February 16, 2016, 11:15:35 PM »
Damn. Gonna get a colony game made before I do, well done sir.

And coding is still largely just gibberish for me. I'm sure what you posted here makes sense, it sure as hell doesn't for me.
-David R.V.

-GMT400 fan
-OPU Influencer

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Re: Learning C++ from a C# background
« Reply #2 on: February 17, 2016, 08:51:37 AM »
@Vagabond: Agreed on all counts.

The wording "const on function variables" sounds a bit strange. I assume you mean how you can declare a member function as const, which means the member function is not able to change any class member variables. It also means that function can be called on a const object, since the compiler can guarantee the member function won't change the object.

I much prefer the naming in the Microsoft world over the C++ standard library world, or the Linux terminal world. Longer spelt out names that don't have random letters dropped are easier to remember, and with code completion available in most editors, really not much more typing. Besides, most of the time spent programming is thinking, not typing, so abbreviating names to the point of obscurity is counter productive.

I hate how C++ requires duplication between header files and implementation files. Ideally, the information needed by a header import can be generated automatically from the source file, which is how pretty much every other language does it these days. I guess computers were simpler and more memory constrained when C++ was first designed though. And yes, it's not ideal that header files contain private implementation details. One of the issues there, is the class size is necessarily a public detail when allocation is done outside the class. This is relevant to both local variables on the stack, where stack frame space needs to be reserved, or when using new/delete, when a size must be passed to the memory allocator. The calling code must know how much space to reserve for the object, and so needs to know the size of the object. The size of course depends on both public and private fields. Still, that's something a compiler can determine by scanning an implementation file and generating some sort of pre-compiled import information. There really should be no need for header files. Also, I hate how constructors are named after the class. This is excessive duplication. If you ever want to change the name of your class, you also have to change the name of all the constructors too. A burden somewhat eased by refactoring tools available in some IDEs, but still unnecessary.


If you're ever in the mood to gripe about C++, go check out the C++ FQA (Frequently Questioned Answers). :p

Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2350
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Learning C++ from a C# background
« Reply #3 on: February 17, 2016, 09:43:26 AM »
Quote
I dislike how classes are declared in header files with all their private members. It is awkward to me to spell out so much implementation up front to the user.
Quote
I hate how C++ requires duplication between header files and implementation files.

This can be solved using the PIMPL idiom. I don't particularly care for it but it's effective in the cases where you want to completely hide implementation details from the user in cases such as libraries (forward declare an implementation class pointer and then define an interface class).

I've thought about using it in NAS2D to prevent the entire world recompiling when I make a simple change but it feels like too much work to define an interface class for every class available in NAS2D. And it's open source. So I didn't.

Offline Vagabond

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1013
Re: Learning C++ from a C# background
« Reply #4 on: February 17, 2016, 05:04:39 PM »
@hooman,

About const, I mean adding it to input variables on a function, I'm probably describing it a little off but here is what I mean:

Code: [Select]
void UseButNoChange(const SomeClass &someClass)

To my knowledge in C# there is no easy way to let someone reference a class by passing it through a method and tell them not to edit it, so it is nice to have this feature in C++.

@Leeor,
I have heard of PIMPL but haven't looked at it closely enough to use yet. I will keep it in mind for if  I start designing more robust classes.

@Dave,
I'm just hoping it will be fun to play. Otherwise it doesn't matter much besides being a learning exercise for me.

----
Made some edits to make what I wrote mean what I was thinking.
« Last Edit: February 17, 2016, 08:35:10 PM by Vagabond »

Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2350
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Learning C++ from a C# background
« Reply #5 on: February 17, 2016, 05:32:39 PM »
What you mean are function parameters.

Quote
To my knowledge there is no easy way to let someone reference a class by passing it through a method and tell them not to edit it.

In C++ declaring a parameter as const is the only way to do this.
« Last Edit: February 17, 2016, 06:15:31 PM by leeor_net »

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Re: Learning C++ from a C# background
« Reply #6 on: February 18, 2016, 05:47:12 PM »
Ahh yes, const function parameters. That's a little more basic than what I was thinking, and much more important.


Although the PImpl (pointer to implementation) idiom is fairly clever in some ways, I can't help but feel it's a bit of a sick hack. It seems to say a lot about the language and its deficiencies, where private data isn't truly private. One of the things I don't like about PImpl is the increased use of dynamic memory for private class data, and the associated costs of managing that memory. It also means access to private class data is indirect, and so takes extra time to access private fields. You can maintain value semantics though, where you just create local variables of the given type, and even if you're using forwarding functions, the compiler can potentially inline them, maintaining direct calls.

A different technique with similar isolation benefits is to use interfaces, and possibly also use factory methods to create objects implementing a specific interface. Interfaces can have the same benefits of hiding implementation details (from users of the object, but not from creators of the object) and speeding up compile times. Interfaces cause an extra layer of indirection when calling functions though, and you lose value semantics. If creating objects indirectly through factory methods (thereby also isolating implementation details for creators of the object), you'll also be using dynamic memory, with the associated costs.

I suppose it's the extra layer of indirection, where private data ends up on the heap, that really buys you the isolation. By moving the private data to the heap, you no longer need to reserve the space for private data on the stack frame, or in containing objects, and so the size of the private data is no longer relevant there.

Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2350
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Learning C++ from a C# background
« Reply #7 on: February 19, 2016, 07:39:02 AM »
Quote
I can't help but feel it's a bit of a sick hack.

That's because it is. It's also why I haven't made any real use of it. It's very, very difficult to convince myself that it's necessary.

Quote
It seems to say a lot about the language and its deficiencies, where private data isn't truly private.

Agreed. C++ is great in a lot of ways. It's also terrible in a lot of other ways.

I like the direct control it gives me over memory management. Something about being that close to the hardware that I like.

At the same time, it's also very hard to manage it properly which is probably why there is so much shitty software out there, including my own. Our monkey brains just aren't really up to the task of truly understanding these things.

Quote
you'll also be using dynamic memory, with the associated costs.

Quote
I suppose it's the extra layer of indirection, where private data ends up on the heap, that really buys you the isolation.

--cough-- managed languages --cough--
« Last Edit: February 19, 2016, 07:41:22 AM by leeor_net »

Offline lordpalandus

  • Banned
  • Hero Member
  • *****
  • Posts: 825
Re: Learning C++ from a C# background
« Reply #8 on: February 25, 2016, 11:48:43 PM »
Question:

Is the data truly private though if you use friend functions to access that data outside of the mutator/accessor member functions that normally accesses that private data in a Class?
Currently working on Cataclysm of Chaos, Remade.
Link to OPU page = http://forum.outpost2.net/index.php/topic,6073.0.html

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Re: Learning C++ from a C# background
« Reply #9 on: February 26, 2016, 12:38:13 AM »
Although it breaks encapsulation slightly, it's done in a controlled explicit manner. Access is still denied by default unless explicitly allowed. You'd normally only use friend within a module of a library where there's already some expectation of sharing of implementation details. I guess this boils down to what you mean by "truly private".

Still, it's fun to remind people:
Friends are allowed access to your private members. ;)

Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2350
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Learning C++ from a C# background
« Reply #10 on: February 29, 2016, 07:38:40 PM »
In my humble opinion, if you're using the friend keyword, you're doing it wrong.

I use it once or twice in NAS2D's classes but I note that it's a hack in the code that needs to be fixed.

Quote
Friends are allowed access to your private members. ;)

Pun number 2, Mr. Hooman.  :P :P :P

Offline lordpalandus

  • Banned
  • Hero Member
  • *****
  • Posts: 825
Re: Learning C++ from a C# background
« Reply #11 on: February 29, 2016, 11:47:37 PM »
Why is using friends doing it wrong, leeor_net? I don't quite understand that statement as I don't understand the context with why you say it. Could you explain that to me please?
Currently working on Cataclysm of Chaos, Remade.
Link to OPU page = http://forum.outpost2.net/index.php/topic,6073.0.html

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Re: Learning C++ from a C# background
« Reply #12 on: March 01, 2016, 01:06:43 AM »
I don't think friend is necessarily wrong, but it's use should be minimal. I also feel friend should be restricted to some kind of package boundary, possibly even to classes/functions in the same file, depending on how granular the file organization is. Remember that friend is exposing private implementation details. If the private implementation is changed, the friend classes/functions will likely also need to be updated. The code structure should reflect this, grouping these details closely together.

A typical use for friend is with operator overloading. You can have overloaded member operators, but then your class must always be the first type. To overload an operator to take a different first type, and your class as a second type, it must be a non-member overload, and so friend can be useful to grant such a function access to internal fields, without having to make them generally public.
Code: [Select]
// Addition should commute
obj + 5; // Can be implemented with an overloaded member operator+
5 + obj;  // Can be implemented with an overloaded friend non-member operator+

// Stream insertion takes a stream object as the first parameter
stream << obj;  // Can be implemented with an overloaded friend non-member operator<<
« Last Edit: March 01, 2016, 01:13:44 AM by Hooman »

Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2350
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Learning C++ from a C# background
« Reply #13 on: March 15, 2016, 03:10:05 PM »
Quote
Why is using friends doing it wrong, leeor_net?

Simple. It breaks encapsulation. If you need to give access to private or protected internal values of a class, then your design is wrong. There are some cases where it's the only clean way to do it.

I used it once in the NAS2D to avoid polluting the interface functions with access to the internal binary data stored as a pointer within the Image resource class and to also prevent client code from having access to the functions that only really OpenGL itself needs FBO's and OGL Texture ID's. It was the simplest way of doing it however I believe that it's fundamentally wrong. FBO's and TextureID's should be handled by the OpenGL renderer alone but that would complicate its internal code... so I opted to do it within Image itself. Again, I believe this to be a flawed design so it conforms to my statement above that if you're doing it that way you're doing it wrong.

Hooman's example I think is the only time I would accept friend as a valid way of doing things.

Keep this statement at heart: Just because you can do something doesn't mean you should.

Chernobyl is a good example. Just because you CAN remove all of the control rods from the reactor doesn't mean you SHOULD. And look at what happened when they DID? Runaway fission reaction leading to a containment vessel breach in the form of an explosion and the worst nuclear disaster the world has ever seen.

Moral of the story is if you use the friend keyword you end in a nuclear disaster.

Or something like that.

Maybe.
« Last Edit: March 15, 2016, 03:13:24 PM by leeor_net »

Offline lordpalandus

  • Banned
  • Hero Member
  • *****
  • Posts: 825
Re: Learning C++ from a C# background
« Reply #14 on: March 18, 2016, 09:23:52 PM »
There is a lot of things with C++ coding that you CAN do but should only do rarely. Like having throwing and catching exceptions occur too often. Or excessive overloading to the point where it is really hard to read the code. Or excessive typedefs that make it impossible for other people to read the code. Etc...

If you truly believe that, then I'm assuming you removed the friend keyword from NAS2D... unless of course you didn't and it did turn into a pile of radioactive goop... figuratively.

Also, I don't know where you got your information from, but I highly doubt that is how Chernobyl occurred; industrial sabotage. Only an idiot or a madman or a saboteur would remove the only thing keeping the reactor stable during reactor operation.

From all the sources I read, what happened was management decided to do an experiment that they thought was safe to do and thus didn't get the head engineer involved. They were trying to do an emergency shutdown procedure test and expected that the test would conclude successfully with no problems. However, due to a variety of structural design problems, and the lack of communication between management and the engineers a variety of unforeseen and unfortunate events occurred leading to the meltdown. From what I read, they did deploy the control rods, however, their control rods were designed, structurally wise, too short and thus weren't as efficient at doing their job and thus couldn't control the temperature spike that they hadn't anticipated. More of anything it is a lesson in proper communication between management and front-line staff than anything. I figure that if the frontline staff were kept in the loop with the test, then they would have been able to prevent the meltdown.
« Last Edit: March 19, 2016, 02:56:58 AM by lordpalandus »
Currently working on Cataclysm of Chaos, Remade.
Link to OPU page = http://forum.outpost2.net/index.php/topic,6073.0.html

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3237
Re: Learning C++ from a C# background
« Reply #15 on: March 19, 2016, 12:22:09 PM »
Moral of the story is if you use the friend keyword you end in a nuclear disaster.

Hitler didn't use the friend keyword.  You don't want to be like Hitler, do you?  :P
"As usual, colonist opinion is split between those who think the plague is a good idea, and those who are dying from it." - Outpost Evening Star

Outpost 2 Coding 101 Tutorials

Offline lordpalandus

  • Banned
  • Hero Member
  • *****
  • Posts: 825
Re: Learning C++ from a C# background
« Reply #16 on: March 19, 2016, 02:23:25 PM »
Neither C, nor C++ existed until the 1970s. So, no, of course he didn't use the friend keyword :P


Currently working on Cataclysm of Chaos, Remade.
Link to OPU page = http://forum.outpost2.net/index.php/topic,6073.0.html

Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2350
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Learning C++ from a C# background
« Reply #17 on: March 22, 2016, 11:20:46 AM »
Quote
Also, I don't know where you got your information from, but I highly doubt that is how Chernobyl occurred; industrial sabotage. Only an idiot or a madman or a saboteur would remove the only thing keeping the reactor stable during reactor operation.

To sum up everything, the junior engineers that were performing the test left the reactor in a very unstable state. Ultimately, the reactor was a piece of shit and had a lot of flaws so it comes as no surprise that the junior engineers they had performing the test ultimately lost control resulting in the explosion that tore the reactor apart.

Quote
If you truly believe that, then I'm assuming you removed the friend keyword from NAS2D... unless of course you didn't and it did turn into a pile of radioactive goop... figuratively.

Nope.

Not yet anyway. It works so I moved on to other parts of the code to get them working too. But it's ugly. And messy. And hardly a good way to do it.

I'll be changing it in a future revision and moving the FBO/Texture ID handling into the OpenGL Renderer instead of handling the implementation details like that within the resource class. It does handle some of the other low level stuff like reference counting, etc. and it seems to do it fairly well though there are certainly ways to break it (e.g., instantiating a Resource class with the New keyword and then not 'Deleting' which either way you look at it is a bug). Anyway, I digress.


Offline lordpalandus

  • Banned
  • Hero Member
  • *****
  • Posts: 825
Re: Learning C++ from a C# background
« Reply #18 on: March 22, 2016, 01:11:41 PM »
Just curious, would using the member access "-> in C++" be a better way of allowing access, rather than using a friend keyword? I ask, because I notice the "->" used quite a bit in class creation in UE4, rather than usage of friend functions.
Currently working on Cataclysm of Chaos, Remade.
Link to OPU page = http://forum.outpost2.net/index.php/topic,6073.0.html

Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2350
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Learning C++ from a C# background
« Reply #19 on: March 22, 2016, 04:51:48 PM »
'->' is used when you're using a pointer to an object. Otherwise if you're using a reference it's simply '.'

This has nothing to do with friend validity, it has to do with dereferencing a pointer to call a function or get a value from an object.

'Friend' allows a another object to call functions or access members declared protected or private by the class. I believe you can also friend stand alone functions that aren't part of an object but I've never tried and I'm too tired to look it up.