views:

311

answers:

5

A child class can access protected functions in parent class,but the parent class can't access protected functions in child class.

I'd like to keep both classes as private as possible.The parent class is a form and only once instance is used.All functions in the child class are static,it inherits from the parent class.

How is it possible to access non-public,static methods in the child class(in another unit) from the parent class?

EDIT:

Parent class(First unit):

interface

type
TParent = class
  public
    procedure Initialize;
  protected
    procedure Test; virtual;
end;

implementation

procedure TParent.Initialize;
begin
  Writeln('Initializing');
  Test;
end;

procedure TParent.Test;
begin

end;

Child class(Second unit):

interface

uses
ParentClass;

type
TChild = class(TParent)
protected
  procedure Test;override;
end;

implementation

procedure TChild.Test;
begin
  Writeln('Test!');
end;

Code(Third unit):

var c:TParent;

begin
  try
    c := c.Create;
    c.Initialize;
    c.Free;
    Readln;
end;

The output is only "initialing".I tried to debug it,it doesn't reach the child class.

+2  A: 

It is not possible to do this. The whole purpose of having non-public methods in the child class is to prevent classes (other than the child class) from being able to access them. Trying to work around this violates basic object oriented principles.

I'd consider rethinking your design.

Reed Copsey
I'd up-vote if you removed the first sentence of the answer - clearly, there _are_ ways around these restrictions. Your (excellent) main point is that this sort of machination is a sign that there's a design problem.
Argalatyr
There are design workarounds to get around the need to do this, but there is no way to directly access a private static method in a subclass class from within the parent class (which was the original question) - hence my comment that this is not possible.
Reed Copsey
+3  A: 

What you want to do violates the Liskov Substitution principle in inheritance. There is probably a better way of doing that. What exactly do you want to do?

EDIT:

Why can't you create the object instance from the child class. You can always assign it to a variable of the type of the parent class. This is commonly done in factory patterns.

txwikinger
A: 

You can do this by registering the child class with the parent when you create it, using some kind of callback (a cattr on the parent, and the child sets when it's defined).

It's rarely the right thing to do, though. Like others have said, consider a different pattern.

I'm not a delphi coder, but you can set a public static variable on the parent class, and set it from a setup method in the child class.

This makes sense in some situations (wanting to pass messages through to class setup methods on a variety of child classes), but there's probably a better way to do what you need. You might want to make your question more about the problem your code is solving.

Michael Sofaer
@Michael,please show some code,I can't do what you said alone.Thank you!
John
That is bad design, comparable to goto spaghetti code
txwikinger
+3  A: 

There actually are several ways to do this, in your parent class, create virtual methods which you call but these do not do anything. In your child classes, override these methods. The methods could easily be protected, but they must exist in the parent.

type
  TParent = class
  protected
    procedure SpecialProcessing; virtual;
  public
    procedure DoWork;
  end;

  TChild = class(TParent)
  protected
    procedure SpecialProcessing; override;
  end;

procedure TParent.DoWork;
begin
  SpecialProcessing;
end;

procedure TParent.SpecialProcessing;
begin
  // does nothing, placeholder
end;

procedure TChild.SpecialProcessing;
begin
  // do special work here
end;

I purposely did NOT make the TParent.SpeciallProcessing abstract. This could be done, but only if TParent would never get created directly, only decendants would be. An abstract method is one which is NOT implemented but is used as a placeholder for implementation by a later child.

To create an instance you use the following:

var
  C : TParent;
begin
  // Create as a TChild, which is a TParent decendant
  C := TChild.Create;
  try
    C.DoWork;
  finally
    C.Free;
  end;
end;
skamradt
skamradt,first thank you for your answer! I like the first way more and I tried to implement it,but the magic didn't work.Please check my question again,I made an edit for you
John
+1  A: 

I might be missing something obvious to the people who already answered. But I think that it's just a matter of instantiating the right object.

The parent code will call the child code, given the object is an instance of the child class.

Try this

var c:TChild;
begin
  c := TChild.Create;
  c.Initialize;
  c.Free;
end.

or even

var c:TParent;
begin
  c := TChild.Create;
  c.Initialize;
  c.Free;
end.
PA