从基类指针访问派生类成员

5

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

示例:

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;
}

1
据我所知,您无法从基类的指针访问派生类的成员。这是因为基类无法以任何方式识别它。但是,您可以从派生类的指针访问基类的成员,因为层次结构表明基类的公共成员现在也是派生类的成员 - user2705585
但是数据在技术上确实存在,对吧?我能使用内存偏移来完成它吗? - Stephen
2
这就是虚方法的用途。如果你还没有在C++课程中学习过虚方法,现在是一个绝佳的机会。 - Sam Varshavchik
可能是C++从基类指针访问派生类成员的重复问题。 - 1201ProgramAlarm
3个回答

6
我无法使用指针符号访问属于派生类的成员。
这是设计上的问题:您没有告诉编译器指针所指向的对象是派生类型。
我能用一个简单的命令访问这些成员吗?
如果您确信指针指向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;
    }
};

我设计算法的方式是,我将始终知道指针指向派生类。因此,这对我的需求非常完美。我尝试了动态转换,但没有考虑到静态转换,谢谢。我将其标记为答案。 - Stephen
你因为完全错误的原因接受了答案。你应该认真考虑使用虚函数。 - n. m.
这个问题是针对一个程序的,其中大部分已经被编写了。我需要这个特定的答案作为快速修复。将来我一定会使用虚函数来完成工作。 - Stephen
虚函数也应该出于正确的原因进行定义和使用。在我看来,这并不是这种情况,而且这个答案提供的解决方案导致了非常薄弱的面向对象编程方法。更好的方法是从关于特定程序的正确问题开始,而不是教条地应用无思考的规则。在这个程序(OP's)中,我会从这个问题开始:如果你知道你需要 bar,那么你为什么要把 B 对象保留在 A 指针中呢?这个问题的答案可能指出重新设计程序的正确方向。 - R.G.

1

阅读type-casting,这是语言中非常基本和重要的方面。

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

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

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

然而,即使该行中的A*实际上并不指向B类型的对象,上述最后一行仍是有效的语句。如果在C对象上尝试该操作,它将编译,但在运行时会导致未定义的行为。
应该提到的是,通常当一个人无法确定他所引用的对象的类型时,程序的更好设计可以从一开始就防止这种情况发生。一个常见的说法是这对于类型转换总体上也是正确的。
P.S. 请注意,在您的代码中,bar是类B的私有成员(我假设这是无意的。任何类的成员默认都是私有的),因此无论如何在B类的实现之外都无法访问。

强制类型转换不是解决问题的正确工具,而且它并不是面向对象编程范式的基本组成部分,后者比任何特定的编程语言都更为重要。请不要使用强制类型转换来掩盖不充分的面向对象设计。 - n. m.
"我认为这是有争议的。" 我不这么认为。 "这是一个技术问题。" 这是一个需要指导的人提出的问题,不是技术上正确但危险的答案。 - n. m.
如果你知道一种“适合工作的正确工具”,并且不改变主题,请分享。已经有一个回答描述了其中一种工具。 - n. m.
因此,在基类中定义任意虚函数,仅用于访问非常特定的派生类成员,这个成员显然不应该被基类或其他无关的派生类所知道,而所有这些都是为了避免向下转换。如果这就是你所谓的OOD,我想这是另一个我们看法不一致的话题。 - R.G.
我的评论在这里超过了允许的评论长度,所以我认为这是不适合进行此类讨论的地方,并且我们可能必须同意不同意见。 :) - R.G.
显示剩余2条评论

0
在您的代码中,派生类的成员是私有的。因此,您无法从基类访问它。 如果您想要访问,必须将派生类的成员更改为“公共”。 您应该像这样修复您的代码:
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;

}


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