tags:

views:

241

answers:

3

Hello All,

I have a general OOP question.

If I have the following classes in C#

class Parent
{
    public string val = "Parent";

    public void getValue()
    {
        Console.WriteLine(this.val);
    }
}

class Child:Parent
{
    public string val = "Child";
}

Child child = new Child();
child.getValue();

The code outputs 'Parent'. As I understand it's because this points to Parent object, right?

If I do the same in PHP5:

class ParentClass {
public $val = 'parent';

    public function foo()
    {
        echo $this->val;
    }
}

class ChildClass extends ParentClass {
public $val = 'child';
}

$a = new ChildClass();
$a->foo();

The result will be 'child'.

Though if I change

public $val = 'parent';

to

private $val = 'parent';

then PHP will also show 'parent'. C# always return 'parent' with both public and private access modifiers.

Is there any reason for this? And which behavior is correct?

Any useful links to read will be highly appreciated!

Thank you!

+4  A: 

There is no correct or incorrect behavior in your stated scenarios. The language designers did what made sense to them.

The reason you don't get the expected behavior in c# is because GetValue is being called in the Parent class, where "this" means the parent val.

To get the correct behavior, you would include the same method in the Child class, with the override keyword:

public class Child
{
    public string val = "Child";
    public override void GetValue()
    {
        Console.WriteLine(val);
    }
}

...which would print "Child" to the console.

Robert Harvey
That being said, the PHP behavior seems more sensible...After all, that is what happens when you override a variable.
Jonathan Sampson
C# allows you to override variables it just requires that you mark them as overridable and explicitly specify that you want to override it. It gives the base class more control over the modifications that can be made to it.
Spencer Ruport
+1  A: 

I think PHP OOP is behaving this way because it does not use the override or virtual modifiers present in other OOP languages. My guess would be that is either a limitation on how PHP works, or it just took too much time to write something that could easily be avoided.

Here's how you would get similar results in C#:

class Parent
{
    // Public identifiers cannot be overridden in C#
    private string _val = "Parent";
    // Public properties can.
    public virtual string val
    {
        get { return _val; }
    }

    public void getValue()
    {
        Console.WriteLine(this.val);
    }
}

class Child : Parent
{
    private string _val = "Child";
    public virtual string val
    {
        get { return _val; }
    }
}
Spencer Ruport
This code doesn't compile.error CS0106: The modifier 'virtual' is not valid for this item
Drew Hoskins
Yeah yeah. I forgot public identifiers cannot be overridden. Fixed.
Spencer Ruport
Thanks. Un-down-voted. :-)
Drew Hoskins
Spencer, shouldn't it be override instead of virtual in the Child class?
dasha salo
@dasha, I should have explained that. For this example either one is fine. If you didn't want the Child.val property to be overridable then yes you would simply use the override keyword. The example I gave both allows the property to be overridden and overrides the property in the parent class.
Spencer Ruport
+1  A: 

PHP's expression is not evaluated until runtime, so it makes sense for it to use the derived class's object. However, C#'s expression is evaluated at compile time. A base class function has no idea whether it will be overridden, so it will reference the string it knows about.

That's where the virtual keyword comes in for functions, which tell the compiler to expect this to be overridden. It will look up the function in the vtable. But there's no equivalent to that for data.

However, you could make it into a virtual property and you would have the behavior you expect. Since properties are functions in disguise, they use the vtable.

Here's the code to achieve the PHP effect.

class Parent{    
    public virtual string val 
    {
        get { return "Parent"; }
    }

    public void getValue()    
    {        
        Console.WriteLine(this.val);    
    }
}

class Child:Parent
{
    public override string val
    {
        get { return "Child"; }
    }
}
Drew Hoskins