基于Is it possible to pass derived classes by reference to a function taking base class as a parameter,请考虑以下示例:
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;
}
上面的代码给出了错误。 是否有任何方法可以将派生类传递给接收基类的函数,而无需在基类中声明派生类的成员?
答案 0 :(得分:1)
监狱。
您可以使用shared_ptr
,dynamic_pointer_cast
和static_cast
进行操作,正如我在上面的代码中向您展示的那样。
顺便说一句,请谨慎设计您的类,因为它在派生和转换时可能会受到影响,正如您在类DerivedB
的第二种情况下所看到的那样,变量{ {1}}被变量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_member
,这是不可能的,因为类Derived
没有变量Base
的定义。
答案 1 :(得分:0)
是否可以将派生类传递给接收基类的函数
是的,如果您将指针或引用传递给基数。
如何将派生类作为函数参数传递
例如:
void func(base* bPtr);
int main(int) {
derived d;
func(&d);
没有在基类中声明派生类的成员吗?
只能在基类的定义中声明基类的成员。派生类的直接成员只能在派生类的定义中声明,尽管基类对象的成员也可以对派生类可见。
您在基类中声明的任何成员都不会影响如何将派生类传递给以基类作为参数的函数。
派生的类成员不在父类中怎么办
然后,您将无法通过指向base的指针访问这些成员。
void func(base * bPtr){ bPtr->derived_member;
确实是上述格式不正确,因为base
没有这样的成员。
为了访问派生类的成员,您应该将指针(或引用,或者可能是副本)传递给派生类:
void func(derived*);
答案 2 :(得分:0)
我相信吗?一旦人们开始学习OOP,这是最流行的设计错误。实际方法应处于完全相反的方向,并应表述为“ Liskov替代原则” https://en.wikipedia.org/wiki/Liskov_substitution_principle
回到我们的案例:因此,您想访问派生成员。问问自己:您因为什么需要会员?因此,与其直接操作字段,不如在基类中提供一个方法。然后,派生类可以使用该派生字段来完成所需的工作。因此,您遇到的问题是因为您试图从中提取部分派生类逻辑。错了!
示例:引擎。基类应具有类似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
暴露给外部世界,因此没有理由。让它们隐藏在内部,将您的基类用作合同,并将派生类用作实现该合同的方式。