我有一个关于继承的基本问题,我似乎可以弄清楚,我已经完成了搜索而没有找到我想要的东西,所以我想我会在这里问(不知道我的标题是什么'我正在寻找是正确的。)
为了简单起见,我已经做了一些示例代码来说明我没有得到的东西。
基本上,如果我有一个父class A
和两个子课B
& C
,
其中A
包含常见内容(例如带有get / set的id
),
而B
& C
具有特定于类的函数。
如果你声明一个类B
,如:A *bObject = new B();
how do you then access the class specific function
bObj-> 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");
}
感谢您的时间!
答案 0 :(得分:0)
A *bobj = new B();
A* cobj = new C();
这里B和C的实例由A的指针指向。由于A没有B和C的成员函数sayHello()和sayGoodbye()的虚函数,它们不能被bobj->sayHello()
和{{1调用}}。这不是多态性应该做的。
A类应该是:
cobj->sayGoodbye()
然后可以在不抱怨的情况下调用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();
。
答案 1 :(得分:0)
A *bobj = new B();
bobj
的静态类型为A *
。因此,在编译时,编译器会在类A
定义中查找成员函数,这是您尝试通过bobj
访问的内容。现在,
bobj->sayHello();
由于sayHello
的类型为A
,编译器将在类bobj
中查找A *
。编译器不关心查看类B
定义来解析调用。由于编译器在sayHello
中找不到A
成员,因此抱怨。
但是,动态类型bobj
为B *
,这是根据动态类型调度调用的位置。
要解决此问题,您需要在virtual
课程中使用A
相同的功能。
答案 2 :(得分: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
来节省运行时检查的成本,但如果指针未指向右侧对象,你会得到未定义的行为。
答案 3 :(得分: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
。请注意,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"
消息。
答案 4 :(得分: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&amp; C是接口类A的实现。
就像你雇人建房一样。你给他们你的蓝图(接口)并雇用他们来构建。你可以随意改变蓝图,他们会在蓝图中做任何事情。但你不能直接订购它们(就像你不能直接从bobj调用sayHello())。