Selecting class at runtime

D

Daniel Bolege

Hello,

I've a problem that drives me crazy. There must be a simple solution, but I
just can't see it. The following code is just a simple example that
demonstrates my problem:

I have an abstract class named "Human" containing members that all derived
classes will need. "Human" does not know anything about its child classes,
so no way for the "virtual/override"-Construct:

1 abstract class Human {
2 public int age = 0;
3 }

Now I have two classes derived from "Human" that contain specific members:

1 class Woman : Human {
2 public void DoFemaleStuff() {
3 System.Console.WriteLine("Go shopping.");
4 }
5 }

and (you guess right)

1 class Man : Human {
2 public void DoMaleStuff() {
3 System.Console.WriteLine("Repair car.");
4 }
5 }

Now, I can do the following trivial stuff:

1 Woman myWoman = new Woman();
2 myWoman.age = 25;
3 myWoman.DoFemaleStuff();
4
5 Man myMan = new Man();
6 myMan.age = 30;
7 myMan.DoMaleStuff();

But, what I want to do is that I only have one human whose sex ist defined
at runtime, like the follwing:

1 if (true) {
2 Woman myHuman = new Woman();
3 myHuman.DoFemaleStuff();
4 } else {
5 Man myHuman = new Man();
6 myHuman.DoMaleStuff();
7 }
8 myHuman.age = 30;

In this example, the compiler says that "myHuman" in Line 8 ist unknown. For
my point of view, this is not correct, although I know that in some
conditional statments more complex than this one a situation may occur
where "myHuman" will not be declared. But I would say, this is the
programmer's, not the comiler's problem.

But the following example fails as well (Note: Class "Human" is now NOT
abstract anymore):

1 Human myHuman;
2 if (true) {
3 myHuman = new Woman();
4 myHuman.DoFemaleStuff();
5 } else {
6 myHuman = new Man();
7 myHuman.DoMaleStuff();
8 }
9 myHuman.age = 30;

Now the compiler says that "myHuman" does not contain a definition for
"DoFemaleStuff" in Line 4 and no for "DoMaleStuff" in Line 7. Aargh!

It seems I just misunderstand a fundamental thing. Any suggestion that
bails me out would be very appreciated.

Daniel
 
N

Nicholas Paldino [.NET/C# MVP]

Daniel,

Why not define your Human class like this:

abstract class Human {
public int age = 0;
public abstract void DoStuff();
}

Then, in your derived male and female classes, you just do this:

class Woman : Human {
public override void DoStuff() {
System.Console.WriteLine("Go shopping.");
}
}

The idea here is that a man and a woman both do "stuff" which is
specific to them being a man or woman (specialization), but at the same
time, as humans, they both have a generic action that they perform. This is
perfect for an abstract method, IMO.

Hope this helps.
 
J

Jon Skeet [C# MVP]

Daniel Bolege said:
But, what I want to do is that I only have one human whose sex ist defined
at runtime, like the follwing:

1 if (true) {
2 Woman myHuman = new Woman();
3 myHuman.DoFemaleStuff();
4 } else {
5 Man myHuman = new Man();
6 myHuman.DoMaleStuff();
7 }
8 myHuman.age = 30;

In this example, the compiler says that "myHuman" in Line 8 ist unknown. For
my point of view, this is not correct, although I know that in some
conditional statments more complex than this one a situation may occur
where "myHuman" will not be declared. But I would say, this is the
programmer's, not the comiler's problem.

No, the compiler is completely correct. The two (distinct) myHuman
variables each only have a scope which is the block you've specified.
The last line is not within the scope of either of them.
But the following example fails as well (Note: Class "Human" is now NOT
abstract anymore):

1 Human myHuman;
2 if (true) {
3 myHuman = new Woman();
4 myHuman.DoFemaleStuff();
5 } else {
6 myHuman = new Man();
7 myHuman.DoMaleStuff();
8 }
9 myHuman.age = 30;

Now the compiler says that "myHuman" does not contain a definition for
"DoFemaleStuff" in Line 4 and no for "DoMaleStuff" in Line 7. Aargh!

It seems I just misunderstand a fundamental thing. Any suggestion that
bails me out would be very appreciated.

You could change line 4 to:

((Woman)myHuman).doFemaleStuff();

and something similar for line 7.

Alternatively, do:

Woman woman = new Woman();
woman.DoFemaleStuff();
myHuman = woman;

etc
 
J

John Wood

C# is strongly typed so you won't be able to access members of derived
classes from your abstract class variable without casting it first.

eg.
((Man)myHuman).DoMaleStuff();

However, to be neatuer the code should probably look like this:

Human myHuman;
if (true) {
Woman myWoman = new Woman();
myWoman.DoFemaleStuff();
myHuman = myWoman;
} else {
Man myMan = new Man();
myMan.DoMaleStuff();

myHuman = myMan;
}
myHuman.age = 30;
 
J

John Wood

Yes, giving some lessons in object orientation is probably a good idea :)

Nicholas Paldino said:
Daniel,

Why not define your Human class like this:

abstract class Human {
public int age = 0;
public abstract void DoStuff();
}

Then, in your derived male and female classes, you just do this:

class Woman : Human {
public override void DoStuff() {
System.Console.WriteLine("Go shopping.");
}
}

The idea here is that a man and a woman both do "stuff" which is
specific to them being a man or woman (specialization), but at the same
time, as humans, they both have a generic action that they perform. This is
perfect for an abstract method, IMO.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)



Daniel Bolege said:
Hello,

I've a problem that drives me crazy. There must be a simple solution,
but
 
D

Daniel Bolege

Hi Nicholas,
Why not define your Human class like this:

abstract class Human {
public int age = 0;
public abstract void DoStuff();
}

Then, in your derived male and female classes, you just do this:

class Woman : Human {
public override void DoStuff() {
System.Console.WriteLine("Go shopping.");
}
}

In this example, it would work, but some "Human" child classes like
"Student" may contain members that do not fit to humans at all, e.g.
"gotoUniversity". As I said, the "Human" class does not know anything about
its child classes, and my example was just to small to demonstrate that.

I will try the casting tip from Jon, but anyway: Thank you very much.

Daniel
 
D

Daniel Bolege

Hi Jon,
No, the compiler is completely correct. The two (distinct) myHuman
variables each only have a scope which is the block you've specified.
The last line is not within the scope of either of them.

Yes sure, you are right. Within a construct like
(for i=0; i<x; i++)
I would not like i to be valid outside as well.
((Woman)myHuman).doFemaleStuff();

That's it! Casting! I knew I overlooked something.

Thanks very much

Daniel
 
N

Nicholas Paldino [.NET/C# MVP]

Daniel,

I would say that in this case, you need to abstract the DoStuff method
out more, to take a parameter indicating what action it should take. This
way, the derived class can decide what things it can do, and then pass along
to the base class whatever parameter(s) you decide to send it (which will
ultimately call the override in the derived class).
 
A

Andreas Müller

Daniel said:
Hello,

I've a problem that drives me crazy. There must be a simple solution,
but I just can't see it. The following code is just a simple example
that demonstrates my problem:

I have an abstract class named "Human" containing members that all
derived classes will need. "Human" does not know anything about its
child classes, so no way for the "virtual/override"-Construct:

1 abstract class Human {
2 public int age = 0;
3 }

Now I have two classes derived from "Human" that contain specific
members:

1 class Woman : Human {
2 public void DoFemaleStuff() {
3 System.Console.WriteLine("Go shopping.");
4 }
5 }

and (you guess right)

1 class Man : Human {
2 public void DoMaleStuff() {
3 System.Console.WriteLine("Repair car.");
4 }
5 }

Now, I can do the following trivial stuff:

1 Woman myWoman = new Woman();
2 myWoman.age = 25;
3 myWoman.DoFemaleStuff();
4
5 Man myMan = new Man();
6 myMan.age = 30;
7 myMan.DoMaleStuff();

But, what I want to do is that I only have one human whose sex ist
defined at runtime, like the follwing:

1 if (true) {
2 Woman myHuman = new Woman();
3 myHuman.DoFemaleStuff();
4 } else {
5 Man myHuman = new Man();
6 myHuman.DoMaleStuff();
7 }
8 myHuman.age = 30;

In this example, the compiler says that "myHuman" in Line 8 ist
unknown. For my point of view, this is not correct, although I know
that in some conditional statments more complex than this one a
situation may occur where "myHuman" will not be declared. But I would
say, this is the programmer's, not the comiler's problem.

But the following example fails as well (Note: Class "Human" is now
NOT abstract anymore):

1 Human myHuman;
2 if (true) {
3 myHuman = new Woman();
4 myHuman.DoFemaleStuff();
5 } else {
6 myHuman = new Man();
7 myHuman.DoMaleStuff();
8 }
9 myHuman.age = 30;

Now the compiler says that "myHuman" does not contain a definition for
"DoFemaleStuff" in Line 4 and no for "DoMaleStuff" in Line 7. Aargh!

It seems I just misunderstand a fundamental thing. Any suggestion that
bails me out would be very appreciated.

Daniel

Most of this straight forward solution has been stated before:

Human myHuman = null;
if (true) {
myHuman = new Woman();
((Woman)myHuman).DoFemaleStuff();
} else {
myHuman = new Man();
((Man)myHuman).DoMaleStuff();
}
myHuman.age = 30;

But as Nicholas suggested, constructs like can and should be replaced by
polymorphism. From my experience, they are a maintainance nightmare.

HTH,
Andy
 
R

Ravichandran J.V.

An abstract class serves as a blueprint for some implementation and
hence, whatever methods that may be used in future, through inheritance,
should be declared as prototypes in the abstract class.

Declare your DoStuff method as virtual so that they could be overridden
in the deriving classes and then, calls to the derived class methods
through an object of type Base Class will work.

with regards,


J.V.Ravichandran
- http://www.geocities.com/
jvravichandran
- http://www.411asp.net/func/search?
qry=Ravichandran+J.V.&cob=aspnetpro
- http://www.southasianoutlook.com
- http://www.MSDNAA.Net
- http://www.csharphelp.com
- http://www.poetry.com/Publications/
display.asp?ID=P3966388&BN=999&PN=2
- Or, just search on "J.V.Ravichandran"
at http://www.Google.com
 

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