C++ 继承抽象函数

c++ inheritance abstract function?

本文关键字:抽象函数 继承 C++      更新时间:2023-10-16

我有一个关于继承的基本问题,我似乎可以弄清楚,我已经进行了搜索但没有找到我要找的东西,所以我想我会在这里问(不确定我正在寻找的标题是否正确)。

为了简单起见,我制作了一些示例代码来说明我没有得到的东西。

基本上,如果我有一个父class A和两个子类B C,其中A包含常见内容(例如带有get/set的id),而BC具有特定于类的功能。如果你声明一个类B如下:A *bObject = new B(); how do you then access the class specific function bObj->specific()'?

我已经尝试过virtual但这需要BC声明相同的函数名称/原型。我也尝试过在A中声明摘要,但这需要它是原型才能在A中。

我哪里出错了? 对此的任何帮助,可能是基本问题都会有所帮助。

#include <iostream>
using namespace std;
// A class dec
class A
{
public:
    A(void);
    ~A(void);
    char id;
    void setId(char id);
    char getId();
};
// B class dec - child of A
class B :
    public A
{
public:
    B(void);
    ~B(void);
    void sayHello();
};
//C class dec - child of A
class C :
    public A
{
public:
    C(void);
    ~C(void);
    void sayGoodby();
};
//a stuff
A::A(void)
{
}
A::~A(void)
{
}
void A::setId(char id)
{
    this->id = id;
}
char A::getId()
{
    return this->id;
}
//b stuff
B::B(void)
{
    this->setId('b');
}
B::~B(void)
{
}
// c stuff
C::C(void)
{
    this->setId('c');
}
C::~C(void)
{
}
void C::sayGoodby()
{
    std::cout << "Im Only In C" << std::endl;
}
// main
void main ()
{
    A *bobj = new B();
    A* cobj = new C();
    std::cout << "im class: " << bobj->getId() << endl;
    bobj->sayHello(); // A has no member sayHello
    std::cout << "im class: " << cobj->getId() << endl;
    cobj->sayGoodby(); // A has no member sayGoodby
    system("PAUSE");
}

谢谢你的时间!

若要访问派生类特有的方法,需要先将基类指针强制转换为正确的派生类类型(向下转换):

A *bobj = new B();
bobj->sayHello(); // compile error
dynamic_cast<B*>(bobj)->sayHello(); // works
dynamic_cast<C*>(bobj)->sayGoodbye(); // run-time error - probably crashes with a segfault/access violation.

dynamic_cast 可确保运行时类型安全,但会给强制转换增加少量开销;对于指针强制转换,如果指向的对象实际上不是 B,则返回 null 指针,您应该在使用它之前检查返回值。或者,如果您确实确定要转换的指针指向正确的对象,则可以使用 static_cast 来节省运行时检查的成本,但如果指针未指向正确的对象,则会得到未定义的行为。

A *bobj = new B();
A* cobj = new C();

这里 B 和 C 的实例由 A 的指针指向。由于 A 没有 B 的虚函数和 C 的成员函数 sayHello() 和 sayGoodbye(),因此它们无法被 bobj->sayHello()cobj->sayGoodbye() 调用。这不是多态性应该做的事情。

A类应为:

class A
{
public:
    A(void);
    ~A(void);
    char id;
    void setId(char id);
    char getId();
    virtual void sayHello(){/* to do */ };
    virtual void sayGoodbye(){ /* to do */ };
};

然后可以调用bobj->sayHello();cobj->sayGoodbye();而无需计划。

A *bobj = new B();

bobj的静态类型为 A * 。因此,在编译时,编译器会在类A定义中查找成员函数,即您尝试通过bobj访问的内容。现在

bobj->sayHello();

编译器将在类 A 中查找sayHello,因为bobj的类型是 A * 。编译器不关心查看类B定义来解决调用。由于编译器没有找到它sayHello A的成员,它正在抱怨。

但是,bobj的动态类型是B *,即根据动态类型调度调用的位置。

要解决此问题,您需要在类 Avirtual相同的函数。

如果你真的想调用这样的函数,你可以这样做:

A* bobj = new B();
((B*)bobj)->sayHello();//this can be dangerous if bobj is not an instance of class B

但是,这里的问题是你做错了设计。基本上,如果您创建一个类 A,并将其子类化为 B 和 C。然后分配 A* bobj = 新的 B();您正在拆分接口和实现。这意味着你将使用 bobj,就好像它是类 A 的实例一样,你不会调用 B 或 C 中的函数。

这就像你雇人来盖房子一样。你给他们你的蓝图(接口)并雇用他们来构建。您可以根据需要更改蓝图,他们将在蓝图中执行任何操作。但是你不能直接订购它们(就像你不能直接从 bobj 调用 sayHello() 一样)。

您可以通过 dynamic_cast<> 使用向下投射。您可以在基类A中实现模板方法,以便于向下转换:

class A
{
public:
    A(void);
    virtual ~A(void);
    char id;
    void setId(char id);
    char getId();
    template <typename CHILD, typename R, typename... ARGS>
    R invoke (R (CHILD::*m)(ARGS...), ARGS... args) {
        CHILD *child = dynamic_cast<CHILD *>(this);
        if (child) return (child->*m)(args...);
        std::cout << "down cast error: " << typeid(CHILD).name() << std::endl;
    }
};

如果A的特定实例不是CHILD的基础,那么dynamic_cast<CHILD *>(this)导致NULL。 请注意,A 中的虚拟析构函数是dynamic_cast<>工作所必需的。

因此,您可以像这样使用它:

std::unique_ptr<A> bobj(new B());
std::unique_ptr<A> cobj(new C());
bobj->invoke(&B::sayHello);
bobj->invoke(&C::sayGoodbye);
cobj->invoke(&B::sayHello);
cobj->invoke(&C::sayGoodbye);

只有第一次和最后一次调用有效。中间的两个将导致打印"down cast error"消息。