0

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

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

基本上,如果我有一个父class A类和两个子类B& C,其中A包含常见的东西(比如id带有 get/set ),而B&C具有特定于类的功能。如果你声明一个类BA *bObject = new B(); how do you then access the class specific functionbObj->specific()`?

我已经尝试过virtual,但这需要B&C声明相同的函数名/原型。我也尝试过在 中声明抽象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");
}

感谢您的时间!

4

5 回答 5

0

您可以通过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。请注意,虚拟析构函数 inA是工作所必需的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"消息被打印。

于 2013-09-10T01:52:12.970 回答
0
A *bobj = new B();
A* cobj = new C();

这里 B 和 C 的实例由 A 的指针指向。由于 A 没有 B 和 C 的成员函数 sayHello() 和 sayGoodbye() 的虚函数,它们不能被bobj->sayHello()and调用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();andcobj->sayGoodbye();可以毫无怨言地被调用。

于 2013-09-10T01:44:43.750 回答
0
A *bobj = new B();

的静态类型bobjA *。因此,在编译时,编译器会在类A定义中查找成员函数,无论您试图通过bobj. 现在,

bobj->sayHello();

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

但是,bobjisB *和 that 的动态类型是根据动态类型调度调用的地方。

要解决此问题,您需要virtual在 class 中使用相同的功能A

于 2013-09-10T01:47:00.143 回答
0

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

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,则它返回一个空指针,并且您应该在使用它之前检查返回值。或者,如果您确实确定要转换的指针指向正确的对象,则可以使用static_cast它来节省运行时检查的成本,但如果指针未指向正确的对象,则会得到 undefined行为。

于 2013-09-10T01:48:48.370 回答
0

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

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 = new B(); 您正在拆分接口和实现。这意味着您将使用 bobj,就好像它是 A 类的实例一样。您不会调用 B 或 C 中的函数。B 和 C 是接口类 A 的实现。

这就像你雇人来建造你的房子一样。你给他们你的蓝图(接口)并雇佣他们来建造。你可以随意改变蓝图,他们会在蓝图中做任何事情。但是您不能直接订购它们(就像您不能直接从 bobj 调用 sayHello() 一样)。

于 2013-09-10T02:05:11.510 回答