How does initializing inherited members inside base class constructor reduce the calls to…?
I’ve read that instead of initializing inherited members ( _c1
in our example ) inside derived constructor:
class A
{
public int _c;
}
class B:A
{
public B(int c)
{
_c = c;
}
}
we should initialize them inside base class constructor, since that way we reduce the calls to inherited members ( _c
):
class A
{
public A(int c)
{
_c = c;
}
public int _c;
}
class B:A
{
public B(int c)
: base(c)
{
}
}
If _c
field is initialized inside base constructor, the order of initialization is the following:
1) First the field initializers of derived class B
are called
A
are called (at this point 开发者_Go百科_c
is set to value 0
)
3) B’s
constructor is called, which in turn calls A’s
custom constructor
4) _c
field gets set to value of a parameter c
( inside A’s
custom constructor )
5) Once A’s
custom constructor returns, B’s
constructor executes its code.
If _c
field is initialized inside B's
constructor, the order of initialization is the following:
1) First the field initializers of a derived class B
are called
A
are called(at this point _c
is set to value 0
)
3) B’s
constructor is called, which in turn calls A’s
default constructor
4) Once A’s
custom constructor returns, B’s
constructor sets _c
field to a value of parameter c
As far as I can tell, in both cases was _c
called two times, so how exactly did we reduce calls to inherited member _c
?
thanx
The problem starts here:
public int _c;
Fields shouldn't be public, so to do this properly you would have a property, and you would therefore have to call the set accessor. I think what they are trying to highlight is the difference between:
private int c;
public int C {get {return c;} set {this.c=value;} } // ld, ld, st
public Foo(int c) {this.c = c;} // ld, ld, st
...
Foo foo = new Foo(blah); // ld, newobj, st
(which does a field assignment inside the constructor)
vs
private int c;
public int C {get {return c;} set {this.c=value} } // ld, ld, st
public Foo() {}
...
Foo foo = new Foo(); // newobj, st
foo.C = blah; // ld, ld, callvirt
However! This is all micro-optimisation. Often, trivial get/set accessors will be inlined - so there is very little difference in reality. I would happily just have:
public int C {get;set;}
Normally you would write class C like this:
class A
{
public A(int c) : _c(c)
{
}
public int _c;
}
And now _c is only set once.
Although in practice I think that compilers optimize this, and your last example will be as fast as this one.
精彩评论