继承 - 无法在派生类中访问基类数据成员

3
在继承中有一个疑问,我有两个类,分别命名为AB
A是基类,B是派生类。 B类继承A类的两个数据成员和两个成员函数。

在派生类中,可以访问静态数据成员,但访问非静态数据成员会导致错误。对于成员函数也是同样的情况,无法访问非静态成员函数。

如果我在任何一个派生类函数内部访问静态或非静态变量 | 函数,它都可以正常工作。

为什么我不能直接在一个类中访问它?为什么当我在任何派生类函数内部访问时不显示错误?请有人澄清我的疑惑。

reference Image

 class A
{
    protected string msg1;
    protected static string msg2;

    protected  string alert1() {
        return "Welcome";
    }
    protected static string alert2()
    {
        return "Welcome All";
    }
}
class B : A {

    string copyMsg1 = msg1;
    string copyMsg2 = msg2;

    string getMsg1 = alert1();
    string getMsg2 = alert2();

    void display() {
        msg1 = "";
        msg2 = "";
        alert2();           
    }
}

1
将代码放在图片的位置,这样我们就可以复制代码。 - Farzin Kanzi
@Farzin Kanzi,请查看我在问题中添加的代码。 - Muthuraman Sundararaj
嗯,alert是一个实例方法。你必须先拥有该类的实例才能访问它。 - Chetan Kinger
1
您无法在字段初始化程序中访问this。无论是同一类成员还是基类成员。 - user4003407
@CKing,我已经在派生类函数 display 中访问了基类的 alert 函数,而没有创建实例。请参考。 - Muthuraman Sundararaj
@MuthuramanSundararaj:CKing的评论是错误的。PetSerAl的评论是正确的。 - Eric Lippert
3个回答

8
这一行是非法的:
string getMsg1 = alert1();

由于它相当于

string getMsg1 = this.alert1();

在字段初始化器中访问this是不合法的。为什么?因为字段初始化器在派生类构造函数或基类构造函数之前运行,因此您可能会调用一个依赖于构造函数已经运行的方法。

正确的解决方案是将初始化放入构造函数中:

class B : A {
  string copyMsg1;
  string copyMsg2; 
  string getMsg1;
  string getMsg2;

  public B() 
  {
    this.copyMsg1 = this.msg1;
    this.copyMsg2 = A.msg2; 
    this.getMsg1 = this.alert1();
    this.getMsg2 = A.alert2();
  }

构造函数体在派生类的字段初始化程序、基类的字段初始化程序和基类构造函数体之后运行。派生构造函数体最后运行,因此您知道它访问的所有内容都已经被创建。
顺便提一下:请注意,在C#中,方法通常以大写字母开头。
此外,在此代码中并没有真正显示出复制的好处。您已经可以从派生类访问基类成员,那么为什么还要将它们复制到派生类中呢?

你讲解得非常好,这个程序没有逻辑,我只是为了解释我的问题而创建它。 - Muthuraman Sundararaj

1
如果我在任何派生类函数中访问静态或非静态变量|函数,它都能正常工作。为什么我不能直接在类中访问?为什么我在任何派生类函数内部访问时不会显示错误。请有人澄清我的疑虑。
换句话说,您的问题是:为什么我可以在类级别(在任何方法或属性之外)访问静态字段,但无法访问实例字段。
静态字段是每个类的。您不需要该类的实例,但需要该类可用。因此,如果该类可用,则可以访问它。
现在让我们转到非静态字段。这是您的类,请注意注释中的数字:
class B : A {

    string copyMsg1 = msg1; <-- 1. assign non-static to non static 
    string copyMsg2 = msg2; <-- 2. assign static to non static

    string getMsg1 = alert1(); <-- 3. non static calling non-static
    string getMsg2 = alert2(); <-- 4. non static calling static

    void display() {
        msg1 = "";
        msg2 = "";
        alert2();           
    }
}
  1. 这是不允许的,因为它们都是实例字段(非静态),并且不能保证此时会有一个A实例可用。
  2. 这是允许的,因为实例字段可以访问静态字段。但反过来不行,因为可能没有实例可用。实例字段、方法和属性可以访问静态和非静态字段。
  3. 由于第1条,这是不允许的。
  4. 由于第2条,这是允许的。

0

在 setter 方法中调用非静态方法:

class A
   {
       protected string alert()
       {
           return "me";
       }
   }

    class B :A
    {
        private string s;

        private void setS()
        {
            s = alert();
        }
    }

这是一个很好的答案。您可以在子类的方法中使用继承的对象。 - Farzin Kanzi
@AliEzzatOdeh,好的,为什么我不能直接访问它呢? - Muthuraman Sundararaj
你不能直接调用非静态方法而不从实例(对象)中调用它,因为非静态方法是针对每个实例的,但你可以从一个方法的实现中调用它,这里是setter,除非创建了一个对象,否则不会被调用。 另一方面,静态方法是共享给所有对象的,因此可以在不创建对象的情况下调用它(直接从类中调用)。 - Ali Ezzat Odeh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接