[英]how to pass a derived class as a function argument: what if the derived class members are not in the parent class
基于是否可以通过引用以基类为参数的函数传递派生类 ,请考虑以下示例:
class base{};
class derived:public base{
public:
int derived_member;
};
void func(base * bPtr){
bPtr->derived_member;
}
int main(int)
{
auto derivedPtr = new derived();
func(derivedPtr);
return 0;
}
上面的代码给出了错误。 有什么方法可以将派生类传递给接收基类的函数,而无需在基类中声明派生类的成员吗?
监狱。
您可以使用shared_ptr
, dynamic_pointer_cast
和static_cast
,如我在上面的代码中所示。
顺便说一句,对类的设计要小心,因为它在派生类和强制转换时可能会受到影响,正如您在类DerivedB
的第二种情况中所看到的那样,变量derived_member
的地址由变量new_member
。
#include<memory>
#include<iostream>
class Base {};
class DerivedA :public Base {
public:
int derived_member;
};
class DerivedB :public Base {
public:
int new_member;
int derived_member;
};
void func(const std::shared_ptr<Base> &bp) {
DerivedA* a = static_cast<DerivedA*>(bp.get()) ;
std::cout << " VALUE MEMBER A: " << a->derived_member << std::endl;
}
int main(int)
{
std::shared_ptr<DerivedA> bpA = std::make_shared<DerivedA>();
std::shared_ptr<DerivedB> bpB = std::make_shared<DerivedB>();
bpA->derived_member = 666;
bpB->new_member = 0;
bpB->derived_member = 667;
std::shared_ptr<Base> pa = std::dynamic_pointer_cast<Base>(bpA);
std::shared_ptr<Base> pb = std::dynamic_pointer_cast<Base>(bpB);
func(pa);
func(pb);
return 0;
}
输出:
VALUE MEMBER A: 666
VALUE MEMBER A: 0
但是,如果您正在寻找一种解决方案,该解决方案意味着无需对Derived
类进行derived_member
就可以调用derived_member
,那么这是不可能的,因为Base
类在其定义中没有变量derived_member
。
有什么办法可以将派生类传递给接收基类的函数
是的,如果您传递了指向基数的指针或引用。
如何将派生类作为函数参数传递
例如:
void func(base* bPtr);
int main(int) {
derived d;
func(&d);
没有在基类中声明派生类的成员?
只能在基类的定义中声明基类的成员。 尽管基类对象的成员也可以在派生类中看到,但是派生类的直接成员只能在派生类的定义中声明。
在基类中声明的任何成员都不会影响如何将派生类传递给以基类作为参数的函数。
如果派生类成员不在父类中怎么办
然后,您将无法通过指向base的指针访问这些成员。
void func(base * bPtr){ bPtr->derived_member;
的确,以上形式不正确,因为base
没有这样的成员。
为了访问派生类的成员,您应该将指针(或引用,或者可能是副本)传递给派生类:
void func(derived*);
我相信? 一旦人们开始学习OOP,这是最流行的设计错误。 实际的方法应该是完全相反的方向,并被表述为“ Liskov替代原则” https://en.wikipedia.org/wiki/Liskov_substitution_principle
回到我们的案例:因此,您想访问derived_member。 问问自己:您因为什么需要会员? 因此,与其直接操作字段,不如在基类中提供一个方法。 然后,派生类可以使用该派生字段来完成所需的工作。 因此,您遇到的问题是因为您试图从中提取部分派生类逻辑。 错误!
例如:引擎。 基类应具有类似startEngeine()
的方法。 然后,汽车引擎应分配以下两个内容:
override startEngeine()
{
isKeyInserted = true;
turnKey();
}
较复杂的引擎可能需要大量的额外工作(此外,它们可能像军车一样根本没有钥匙)
override startEngeine()
{
checkOilLevel(); // can throw if oil level is low
while (oilPressure < 10)
{
activateOilPump();
}
activeCylindersCount = 4;
isStarterActive = true;
... etc ...
}
因此,在您的情况下,您尝试将isKeyInserted
和activeCylindersCount
暴露给外部世界,没有任何理由。 让它们隐藏在内部,将您的基类用作合同,并将派生类用作实现该合同的方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.