Reputation: 16389
Purpose of question is to understand how inheritance works under the hood; I am aware about what it is and when to use it.
Following is use case -
class A {}
class B : A {}
class C
{
B b = new B();
}
Now, how many objects (EXCLUDING the one for C class as it will be entry point and any default DotNet/CLR objects) are created in memory? Is it two (one for A and other for B)? Or is it only one for B which also contains members of A? Some explanation will help.
Upvotes: 1
Views: 1515
Reputation: 63732
Since it seems that the purpose of your question is to basically to see the "physical" difference between using composition and inheritance, I'm going to focus on that.
When you use new
, a single instance of the type is created, and the appropriate constructor of the type (and all of its "parents") is executed once.
In C#, the default inheritance approach (the B : A
kind) is subclassing. In this approach, a derived class is basically a copy of its parent, plus the instance fields of the derived class, plus the metadata associated with e.g. any new virtual methods.
This means that in your case, calling new B()
only creates a single object instance, and that's it. The instance of B
contains within itself the fields and metadata of A
, but not a reference to an instance of A
.
If you define B2
like this:
class A2
{
int myInt;
}
class B2
{
A2 aInstance = new A2();
}
Then the B2
constructor also creates an instance of A2
, so you have two object instances, one of type A2
, another of type B2
. B2
only contains a reference to the A2
instance, rather than a copy of it.
How does this translate to runtime costs?
A2
will tend to be allocated right behind B2
.The result? Well, I don't think it's something you need to care about much in advance. There is a cost to having the extra instances, but unless you're allocating millions of instances, it probably isn't going to make much of an observable difference. If your application allows it, you might even have a net gain, since the composition model can allow you to reuse the same instance in multiple places which simply isn't possible with subclassing. Sometimes this makes sense, sometimes it doesn't :)
And of course, note that you don't always have to use classes. For example, A2
can easily be a struct
, eliminating the extra instance - again, impossible with subclassing, since struct
s can't be inherited from. In that case, the two approaches become equivalent.
As is usually the case with performance, you really need to do practical profiling to get your answer. And the result will probably be something like "99.9% of the code performs fine, but this one class could save us a lot of CPU/RAM if we changed it to a struct
and moved the polymorphism to a higher layer".
Finally, I'm pretty sure none of this is part of the contract. If Microsoft decides to change the way inheritance works in a future version of the .NET framework, and makes it create a new instance instead of "inlining" the parent, I don't think it's going to violate the specification in any way. Unless you absolutely need to depend on this information, don't.
Upvotes: 2
Reputation: 26408
For the sake of argument lets say you make an instance of C
var c = new C();
at this point you have two object instances, because during construction C
makes an instance of B
.
To answer your question, You have an instance of C
and an instance of B
. You don't have an instance of A
, even though B
is derived from A
. (Update: Ignoring C
and any reflection, you have one object instance of B
. )
You can prove this with some code:
class A { }
class B : A { }
class C
{
public B B = new B();
}
class Program
{
static void Main(string[] args)
{
var c = new C();
var b = c.B;
var BasA = (A)b;
bool BisA = BasA.GetType() == typeof (A);
Console.WriteLine($"Assert That B is not A: {!BisA}");
}
}
Plus, You can see all your memory via the debugger:
Also be careful with terminology. A
, B
and C
are classes. Objects are instances of classes. In C# the information that describes a class can be encapsulated in an instance of a System.Type
class.
So lets go down the rabbit hole a little; How many objects do you have in memory, in a executing assembly?
Limiting our scope to those classes only, in addition to the two objects you get from instanciating C
, you will also have three instance of System.RuntimeType
one for A
, B
and C
:
var assemblyTypes = Assembly.GetExecutingAssembly().GetTypes();
foreach (var classType in assemblyTypes)
Console.WriteLine("Type instance: " + classType);
Again, this is showing how you have three instance of System.RuntimeType
, that describe the classes A
, B
and C
.
Being pedantic, you will also get an instance of RuntimeAssembly
(for your executable) and RuntimeType
(for your console Program class), as well as others
Upvotes: 4
Reputation: 450
If you ignore C
(as program entry) there will be one B
object and two System.RuntimeType
objects that describe the A
and B
classes.
Refer to CLR via C#, Fourth edition, P100-110
Upvotes: 1
Reputation: 679
New objects are created when you use keyword new.
The source code is more like a blueprint where for simplicity you specify that one object extends behavior and members of another object (inherits it). This information is needed for describing the type itself. The actual object is constructed based on the description of the type by using the new keyword.
In your case only one object will be created.
Upvotes: 1