Inheritance & Constructors

Y

yuriy_zubarev

Greetings,

I have 2 classes:

abstract class Abstract
{
public Abstract()
{
}

public Abstract(string name): this()
{
}

}

class Impl: Abstract
{
public Impl(): base()
{
// Some important code
}

public Impl(string name): base(name)
{
}
}

While doing the following, the constructor with "Some important code"
doesn't get invoked:

Abstract obj = new Impl("cute name");

What's the proper way of organizing classes in this case? I need code
from Impl() constructor to be invoked when instantiating a class by
using Impl(string) constructor and of course, constructors from
abstract class shouldn't be forgotten either.

Thank you for your time.

Regards.
 
J

Jon Skeet [C# MVP]

yuriy_zubarev said:
I have 2 classes:

While doing the following, the constructor with "Some important code"
doesn't get invoked:

Abstract obj = new Impl("cute name");

No, it wouldn't.
What's the proper way of organizing classes in this case? I need code
from Impl() constructor to be invoked when instantiating a class by
using Impl(string) constructor and of course, constructors from
abstract class shouldn't be forgotten either.

A few options:

1) Put all the code which needs to be run from all constructors into
another method, and call that at the start of each constructor.

2) Put it in the constructor which takes all parameters, and make the
parameterless constructor call that one rather than the other way
round. (That would mean a different base class constructor being called
too, of course.) This method won't always work, depending on what you
need to do.
 
B

Bruce Wood

My general rule is that (unless there is a pressing reason why not)
constructors with fewer arguments should call the "master constructor"
that takes the most arguments. This makes constructors with fewer
arguments into mere abbreviations for calling the "master constructor".

So, in your Abstract class, I would rewrite it like this (assuming that
the default value for your "name" is an empty string):

public abstract class Abstract
{
public Abstract() : this("")
{ }

public Abstract(string name)
{
...
}
}

The only problem is that now this falls down when you introduce
inheritance. In the inherited class, you have two equally unattractive
alternatives. The first is to duplicate the knowledge that the default
name is an empty string. Now both the base class and the derived class
know this, but at least the derived class can use the same pattern
again:

public class Impl : Abstract
{
public Impl() : this("")
{ }

public Imple(string name) : base(name)
{
// Some important code here
}
}

The other approach is to have each derived class constructor call the
corresponding base class constructor, and make a private method for
initializing the derived class:

public class Impl : Abstract
{
public Impl() : base()
{
InitializeMe();
}

public Impl(string name) : base(name)
{
InitializeMe();
}

private void InitializeMe()
{
// Do something important here
}
}

Myself, I tend to prefer the first form. Most of the time the "what is
the default value for the parameters" secret isn't so earth-shattering
that it can't be duplicated in the derived class, and the code is much
easier to read. (Although the reader may miss the fact that defaulting
is being done in two or more places, and screw that up during
maintenance.)

The second form, while it's better from an encapsulation point of view,
just looks ugly to me.
 
Y

yuriy_zubarev

Thank you,

Interestingly enough, I used both methods in the past depending on
circumstances but only today it hit me that I've been going around
language deficiencies (may be a little bit strong of a term). So I was
just wondering if I simply missed some basics.

Regards.
 
Y

yuriy_zubarev

Thanks a lot for sharing your point of view!

I used both approaches in a project some time ago just to see which
one whould stand the test of times. Now I'm in a process of enhancing
the project and I'm facing those approaches again. From my experience I
can already say that neither is trully superrior. I cannot help but
think that c# missed something here...

Regards.
 
B

Bruce Wood

I haven't run across an O-O language that has cleanly solved this
problem. If I recall correctly, C++ and Java share this same problem
(with different syntax, of course).

(He says, waiting for the Delphi types to chime in and say that once
again Delphi has an elegant solution to this problem.... :)
 
B

branco.medeiros

Hi, yuriy.

My opinion is that you're being victim of the illusion that the derived
class must follow the same creation syntax of the base class. This is
just an illusion. If not, then there would be no place for, say
(forgive my C#):

class Impl2: Abstract {
public Impl2(int number): base() {

}
}

If your derived class needs to call syntactically similar constructors
from the ancestor while relying on a specific execution path through
its own constructors, then your best approach, it seems, is to rely on
auxiliary methods to perform the actual initialization (no matter how
ugly they seem, because, after all, uglier were the actual
requirements):

class Impl2: Abstract {
public Impl2(): base() {
Initialize();
//...
}

public Impl2(string name): base(name) {
Initialize();
//...
}
public Impl2(int number): base() {
Initialize();
//...
}

private void Initialize() {

}
}

Regards,

Branco.


yuriy_zubarev wrote:
abstract class Abstract
{
public Abstract()
{
}

public Abstract(string name): this()
{
}

}

class Impl: Abstract
{
public Impl(): base()
{
// Some important code
}

public Impl(string name): base(name)
{
}
}

While doing the following, the constructor with "Some important code"
doesn't get invoked:

Abstract obj = new Impl("cute name");
<cut>
 
J

Joanna Carter \(TeamB\)

I haven't run across an O-O language that has cleanly solved this
problem. If I recall correctly, C++ and Java share this same problem
(with different syntax, of course).

(He says, waiting for the Delphi types to chime in and say that once
again Delphi has an elegant solution to this problem.... :)

Hello, did someone call ? :)

Yes Delphi does allow this behaviour because it allows virtual constructors.
Therefore you can mark the base constructors as virtual or abstract and the
derived classes as override.

Unfortunately, this is not the case with C#, although Delphi 2005 for .NET
still allows you to use both virtual constructors and static methods!!

The best solution I can think of is to use what is called the Template
Method or Strategy pattern :

abstract class Abstract
{
protected abstract void ImportantCode();

public Abstract()
{
ImportantCode();
}

public Abstract(string name) : this()
{
}
}

class Impl : Abstract
{
protected override void ImportantCode()
{
Console.WriteLine("Impl.ImportantCode");
}

public Impl(): base()
{
}

public Impl(string name) : base(name)
{
}
}

Joanna
 
B

Bruce Wood

The only difficulty with this method, in C# and in Java, is that you
have to remember that when ImportantCode is called in the derived
class, the derived class constructor hasn't run yet, and so the derived
class variables are all at their default values... they have not yet
been initialized by the derived class constructor.

I find this practice dangerous because it's easy for an inexperienced
(or sleepy) programmer to miss this detail and assume that the
ImportantCode method is running inside a properly constructed object.
(Usually this "forgetting" comes in the form of having ImportantCode
call other "useful" methods within the derived class, forgetting that
those methods can't be called yet becaues the object isn't initialized
yet. Can you tell I've done it? :)
 
J

Jon Skeet [C# MVP]

Bruce Wood said:
The only difficulty with this method, in C# and in Java, is that you
have to remember that when ImportantCode is called in the derived
class, the derived class constructor hasn't run yet, and so the derived
class variables are all at their default values... they have not yet
been initialized by the derived class constructor.

There's an important difference between C# and Java here - although in
both the constructors haven't been called, in C# the variable
initialisers are called *before* the base constructor is called,
whereas in Java they're called *after* the base constructor is called.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top