By analogy, C# is basically like a set of mechanic's tools where somebody has read that you should generally avoid pliers and adjustable wrenches, so it doesn't include adjustable wrenches at all, and the pliers are locked in a special drawer marked "unsafe", and can only be used with approval from a supervisor, after signing a disclaimer absolving your employer of any responsibility for your health.
C++, by comparison, not only includes adjustable wrenches and pliers, but some rather odd-ball special purpose tools whose purpose aren't immediately apparent, and if you don't know the right way to hold them, they might easily cut off your thumb (but once you understand how to use them, can do things that are essentially impossible with the basic tools in the C# toolbox). In addition, it has a lathe, milling machine, surface grinder, metal-cutting band-saw, etc., to let you design and create entirely new tools any time you feel the need (but yes, those machinist's tools can and will cause serious injuries if you don't know what you're doing with them--or even if you just get careless).
That reflects the basic difference in philosophy: C++ attempts to give you all the tools you might need for essentially any design you might want. It makes almost no attempt at controlling how you use those tools, so it's also easy to use them to produce designs that only work well in rare situations, as well as designs that are probably just a lousy idea and nobody knows of a situation in which they're likely to work at all well. In particular, a great deal of this is done by decoupling design decisions--even those that in practice really are nearly always coupled. As a result, there's a huge difference between just writing C++, and writing C++ well. To write C++ well, you need to know a lot of idioms and rules of thumb (including rules of thumb about how seriously to reconsider before breaking other rules of thumb). As a result, C++ is oriented much more toward ease of use (by experts) than ease of learning. There are also (all too many) circumstances in which it's not really terribly easy to use either.
C# does a lot more to try to force (or at least extremely strongly suggest) what the language designers considered good design practices. Quite a few things that are decoupled in C++ (but usually go together in practice) are directly coupled in C#. It does allow for "unsafe" code to push the boundaries a little, but honestly, not a whole lot.
The result is that on one hand there are quite a few designs that can be expressed fairly directly in C++ that are substantially clumsier to express in C#. On the other hand, it's a whole lot easier to learn C#, and the chances of producing a really horrible design that won't work for your situation (or probably any other) are drastically reduced. In many (probably even most) cases, you can get a solid, workable design by simply "going with the flow", so to speak. Or, as one of my friends (at least I like to think of him as a friend--not sure if he really agrees) likes to put it, C# makes it easy to fall into the pit of success.
So looking more specifically at the question of how class
and struct
got how they are in the two languages: objects created in an inheritance hierarchy where you might use an object of a derived class in the guise of its base class/interface, you're pretty much stuck with the fact that you normally need to do so via some sort of pointer or reference--at a concrete level, what happens is that the object of the derived class contains something memory that can be treated as an instance of the base class/interface, and the derived object is manipulated via the address of that part of memory.
In C++, it's up to the programmer to do that correctly--when he's using inheritance, it's up to him to ensure that (for example) a function that works with polymorphic classes in a hierarchy does so via a pointer or reference to the base class.
In C#, what is fundamentally the same separation between the types is much more explicit, and enforced by the language itself. The programmer doesn't need to take any steps to pass an instance of a class by reference, because that'll happen by default.
struct
s aren't always stored on the stack; consider an object with astruct
field. That aside, as Mason Wheeler mentioned the slicing problem is probably the biggest reason.