2009-12-04 4 views
3

클래스 A가 클래스 B에서 상속 받고 클래스 C에서 상속 받았다고 가정 해 봅시다. 가상 메소드 void f()가 A에서 정의되었으며 B와 C에서 모두 재정의 된 것으로 가정합니다. 모든 메소드에서 Bf()를 호출합니다. in A는 단순히 base.f()를 사용하여 수행 할 수 있습니다. C.f()를 A의 메소드에서 호출하는 것은 어떻습니까?C# 기본 자료에서 메소드를 호출하는 방법은 무엇입니까?

+4

가능한 중복 : http://stackoverflow.com/questions/1006530/c-how-to-call-a-second-level-base-class-method-like-base-base-gethashcode – itowlson

+0

나는 가정 Af()를 C의 메서드에서 호출하는 것을 의미합니까? –

+0

저는 정말로 추측하고 있습니다 만, C에게'this'을 던질 수는 없습니까? ((C) this) .f(); –

답변

10

일반적으로 클래스를 재정의하면 인터페이스 및 원하는 일부 동작을 제공한다는 것을 인정하게됩니다. A는 수퍼 클래스에 의해 명시 적으로 노출되지 않는 한 슈퍼 수퍼 클래스임을 알지 못합니다. B를 서브 클래스화할 때 C가 구현되는 방법을 알 필요가 없기 때문에 이것은 실제로 바람직합니다. C가 관련되어 있다는 것을 알지 못합니다.

b의 f()가 base.f()를 호출하면 a의 base.f()가 자신의 base.f()를 호출하면 완료됩니다. 그렇지 않다면 자신을 수행 할 수있는 유일한 방법은 리플렉션을 기반으로하는 침입 방법입니다. 자신이이 작업을 수행해야하는 경우 설계에 오류가있는 것입니다 (Demeter의 법칙을 위반 함).

+0

감사합니다. 내 자신의 디자인이 아닙니다. 이 경우 클래스 B와 C는 Telerik 구성 요소입니다. B 클래스는 필자가 필요로했던 대부분의 기능을 제공하지만 C에서 메소드를 호출 할 때 필요한 기능 중 일부를 구현하기 위해 사용되었다. – sisis

0

이 시도 :

C c = this; 
c.f(); 

이 인쇄 "C"를 :

public static void Main() 
{ 
A o = new A(); 
Console.WriteLine(o.f()); 
} 

class C 
{ 
public virtual string f() 
{ 
    return "C"; 
} 
} 

class B : C 
{ 
public virtual string f() 
{ 
    return "B"; 
} 
} 

class A : B 
{ 
public virtual string f() 
{ 
    C c = this; 
    return c.f(); 
} 
} 
+0

컴파일 할 때 보이지 않습니다 (어쨌든 시도해보십시오). 당신은 C++에 대해 생각하고 있습니까? * 상속 체인에서 메소드를 호출 할 때 비슷한 구문을 사용합니까? – itowlson

+0

이것은 컴파일되지도 않고 이론적으로도 작동하지 않습니다. 정적 인 경우가 아니라면 그러한 메소드를 호출 할 수 없습니다. 이러한 경우 정적 인 경우가 아니면 가상 일 수 없습니다. –

+0

죄송합니다. 나는 판단력이 일시적으로 상실되었습니다. 해결 방법으로 수정되었습니다. – Jason

1

이는 반사를 통해 수행 할 수 있습니다. 현재 클래스의 Type을 가져 와서 상위 유형을 가져온 다음 상위 유형의 상위 유형을 가져옵니다.

언어에서 직접 지원되지 않는 이유는 상속의 추상화 모델을 손상시키기 때문입니다. 그것은 기존의 객체 지향 설계와 실제로 호환되지 않습니다.

3

리플렉션을 통해 또는 IL 코드를 생성 할 수 있습니다. 그것 이외에, 당신은 할 수없고, 정말로 그렇게해서는 안됩니다. 이것은 좋은 디자인처럼 들리지 않습니다.

OOP에서 메서드를 재정의 할 때 기본적으로 "이 형식의 경우이 메서드는 이전 메서드를 바꿉니다"라는 말을 필요에 따라 (일반적으로는 가능) 대체 된 재정의 된) 메소드를 호출합니다.

그러나 반성이나 일리노이 속임수에 의지하지 않는 한 직접 레벨을 건너 뛸 수는 없으며, 그럴만한 이유가 있습니다. 중간 클래스가이 메서드 호출을 위해 중간 클래스를 건너 뛸 수 있도록 허용해야한다면 사용할 수있는 특별한 메서드를 추가해야합니다. 이것이 "어렵다"하는 이유는 일반적으로 그렇게해서는 안되며 항상 다음 단계로 올라가서 통제 할 수 있어야하기 때문입니다.

1

C의 메서드에서 A.f()를 호출한다고 가정합니까?

짧은 답변 :

protected void BaseF() 
{ 
    base.f(); 
} 

을 그리고 그때부터 그 메소드를 호출하면 B를 제어 할 수 있다면 당신은

그러나, 당신은 명시 적으로 기본 전화 B로 방법을 추가 할 수 없습니다 C

0

C의 함수에서 base.f(), 을 호출 할 수 있습니다.이 작업은입니다. 만약 당신이 실제로 부르는 B.f()가 base.f()를 호출하기를 원한다면, 그것은 당신이 원하는 것을 얻는다. 그러나 그것이 일어 났는지 아닌지에 대해서는 B의 구현에 달려있다.

당신은 다음과 같이 A와 C 및 호출 F()를 주조 시도 할 수 있습니다 :

public class C : B { 
    public override f() { 
     ((A) this).f(); 
    } 
} 

하지만,이 문제는 C는 F()가 선언 아무 생각이없는 것입니다 - 그것은 알고있는 모든이다 재정의 될 수있는 B에서의 구현이 있다는 것을 C가 알지 못한다. 위 예제는 실제로 코드의 나쁜 부분이며, A가 f()를 구현하지 않으면 컴파일 타임 오류가 발생합니다.

0

override이 아닌 사용은 일 수 있습니다 (이 기능은 사용할 수는 있지만 new을 사용하려면 가상 일 필요가 없습니다).

그래도 다른 문제가 발생할 수 있습니다. MyClassMyBaseClass으로 업 캐스트하면 MyBaseClass 버전의 기능이 사용됩니다.

private void Form1_Load(object sender, EventArgs e) 
{ 

    var mc = new MyClass(); 

    mc.Foo(); 
    ((MyBaseClass) mc).Foo(); 
} 


public class MyBaseClass 
{   
    public virtual void Foo() 
    { 
     Console.WriteLine("Calling from MyBaseClass"); 
    } 
} 

public class MyClass : MyBaseClass 
{ 

    new public void Foo() 
    { 
     Console.WriteLine("Calling from MyClass"); 
    } 
} 

당신이 얻을 출력은 다음과 같습니다

Calling from MyClass 
Calling from MyBaseClass 
0

으로는 이전에 주석하고, 가상이 방법에서 재정의 될 수 없다, 당신은 '새로운'대신 '무시'로 사용해야합니다. 그것은 매우 혼란 얻고 예상되는 상속 동작의 대부분을 파괴하고, '새로운'키워드가 새로운 인터페이스를 강제하기위한 것입니다으로, 이것은 좋은 방법이 아닙니다

:

여기에 클래스 이름을 사용하는 예입니다 항목을 재정의하려는 클래스에 추가하십시오.

건배, 제이슨

class Program 
{ 
    static void Main(string[] args) 
    { 
     C c = new C(); 
     A a = new A(); 
     a.DoThis(); 
     Console.ReadKey(); 
    } 
} 

public class C 
{ 
    public virtual void DoThis() { 
     Console.WriteLine("In C"); } 
} 

public class B : C 
{ 
    public new void DoThis() 
    { 
     Console.WriteLine("In B"); 
    } 
} 

public class A : B 
{ 
    public new void DoThis() 
    { 
     Console.WriteLine("In A.."); 
     ((C) this).DoThis(); 
    } 
} 
0

이것은 설계 문제처럼 보인다.

옵션의 몇 당신은 :

  1. 는 A.DoThis()의 대부분을 가지고, 그리고 (보호는?) 적절한 무엇인가라는 또 다른 방법으로 이동 (DoThat()?). 이제 직접 호출 할 수 있습니다.
  2. 개체를 분할하고 상속보다는 구성을 사용하여 동작을 다시 사용하는 것이 좋습니다.
관련 문제