【问题标题】:Access member of derived class from pointer of base class从基类的指针访问派生类的成员
【发布时间】:2016-07-31 05:11:58
【问题描述】:

我有一个派生自另一个类的类,我使用基类指针数组来保存派生类的实例,但由于该数组属于基类,我无法使用指针访问属于派生类的成员表示法,我是否可以通过简单的命令访问这些成员,还是应该重写我的基类来定义成员并只在派生类中使用它?

例子:

class A {
public:
    int foo;
};

class B : public A {
public:
    char bar;
};

class C : public A {
    int tea;
};

int main() {
    A * arr[5];
    arr[0] = new B;

    char test = arr[0]->bar; //visual studio highlights this with an error "class A has no member bar"

    return 0;
}

【问题讨论】:

  • 据我所知,您不能从基类的指针访问派生类的成员。仅仅是因为基类无论如何都无法识别它。但是,您可以从派生类的指针访问基类的成员,因为层次结构说基类的公共成员现在也是派生类的成员
  • 但是数据在技术上是存在的吧?我可以使用内存偏移量吗?
  • 这就是虚拟方法的用途。如果您尚未了解 C++ 类中的虚拟方法,那么现在是学习的绝佳机会。

标签: c++ class pointers polymorphism


【解决方案1】:

我无法使用指针表示法访问属于派生类的成员

这是设计使然:您没有告诉编译器指针指向的对象是派生类型。

我是否可以通过简单的命令访问这些成员

如果你 100% 确定指针指向 B,你可以执行 static_cast<B*>(arr[0]),但应该使用强制转换解决方案作为最后的手段。相反,您应该在基类中派生一个成员函数,并在派生类中提供一个实现:

class A {
public:
    int foo;
    virtual char get_bar() = 0;
};

class B : public A {
    char bar;
public:
    char get_bar() {
        return bar;
    }
};

【讨论】:

  • 按照我设计算法的方式,当指针指向派生类时,我总会知道。所以这非常适合我的需要。我尝试了动态演员表,但我没想过要做静态演员表,谢谢。我将此标记为答案。
  • 您已经接受了所有错误原因的答案。您应该认真考虑使用虚函数。
  • 这个问题是针对一个程序的,其中大部分已经写好了。我需要这个特定的答案作为快速修复。以后我一定会使用虚函数来完成这项工作。
  • 虚函数也应该被定义并用于正确的理由。在我看来,情况并非如此,并且此答案中提供的解决方案导致 OOP 方法非常薄弱。更好的方法是从关于特定程序的正确问题开始,而不是教条地应用轻率的经验法则。在这个程序(OP's)中,我会从一个问题开始:如果你知道你需要bar,那么为什么你从一开始就将B 对象保留在A 指针中?这个问题的答案可以指出重新设计程序的正确方向。
【解决方案2】:

了解type-casting,这是语言的一个非常基本和重要的方面。

简而言之,您始终可以将指向基址的指针强制转换为指向派生的指针,然后引用其唯一的公共成员。

A * arr[5];
arr[0] = new B;

char test = static_cast<B*>(arr[0])->bar;

但是,即使A* 并没有真正指向B 类型的对象,上面的最后一行也是一个有效的语句。如果您在 C 对象上尝试这样做,它将编译,并在运行时导致未定义的行为。

但是应该提到的是,通常当一个人不能确定他所指的对象的类型时,一个更好的程序设计可能会从一开始就阻止它。一个常见的说法是,一般情况下类型转换都是如此。

附:请注意,在您的代码中,barclass B 的私有成员(我假设是无意的。默认情况下,class 的任何成员都是私有的),因此在 class B 实现之外无论如何都无法访问。

【讨论】:

  • 铸造不是适合这项工作的工具,如果面向对象编程范式,它不是基本方面,这比任何特定语言都更重要。请不要使用强制转换来掩盖 OO 设计的不足。
  • 我相信这是有争议的。据我了解,这个问题与 OOD 无关。这是一个技术问题,类型转换是问题形成方式的直接答案。如果您知道不会改变主题的“适合工作的工具”,请这样做。
  • “我相信这是有争议的”。我不。 “这是一个技术问题”。这是某个需要指导的人提出的问题,不是技术上正确但危险的答案。
  • “如果你知道一个不会改变话题的“适合工作的工具”,请这样做”。已经有一个描述一个答案。
  • 所以,在基类定义一个任意虚函数,只是为了访问一个非常具体的派生类的一个非常具体的成员,这个成员显然甚至不应该是已知 由基类或其他不相关的派生类组成,所有这些都是为了避免向下转换。如果这就是你所说的 OOD,我想那是另一个我们不一致的话题。
【解决方案3】:

对于您的代码,您的派生类成员是私有的。因此,您无法从基类访问它。 如果要访问,必须将派生类的成员更改为“public”。 你应该像这样修复你的代码:

class B : public A {
public:
    char bar;
};

int main() {
A * arr[5];
arr[0] = new B;

char test = static_cast <B *>(arr[0])->bar; //visual studio highlights this with an error "class A has no member bar"
return 0;

}

【讨论】:

    猜你喜欢
    • 2011-01-27
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-01
    • 1970-01-01
    相关资源
    最近更新 更多