如果我有一个指向超类的指针向量并将子类的成员添加到向量中,我可以很好地调用子类函数,但是因为我的代码现在是正确的,所以我无法访问特有的变量。子类。如何从B
中的指针访问vec
?
#include <iostream>
#include <vector>
class Super {
public:
int A;
Super(int a) : A(a) {}
virtual void foo() = 0;
};
class Sub : public Super {
public:
int B;
Sub(int a, int b) : Super(a), B(b) {}
void foo() {
std::cout << "calling foo from Sub\n";
}
};
int main() {
std::vector<Super*> vec;
vec.push_back(new Sub(2, 3));
vec[0]->foo(); // No problem
std::cout << "A: " << vec[0]->A << std::endl; // No problem
std::cout << "B: " << vec[0]->B << std::endl; // Compile Error
}
答案 0 :(得分:1)
它取决于设计。 &#34;强制执行&#34;这样做的方法是将值转换为子类型,例如:
std::cout << static_cast<Sub*>(vec[0])->B;
现在,为什么这很糟糕是因为你明确地将一种类型转换为另一种类型,这本身就违背了抽象和继承的目的。
这就是为什么在常见用法中发生的事情是你在超类中定义一组类型的特征,然后在子类中扩展或实现它。现在这不可能,就像你的测试案例一样,但原则上这就是你应该照顾的原因。
答案 1 :(得分:1)
如果可以保证每个指针都指向dynamic_cast<Sub*>
,你可以用static_cast<Sub*>
(甚至是Sub
天真地修复它,但是......不要!这是虚拟调度的教科书案例。
我添加了virtual void print(std::ostream&)
整个继承层次结构的接口的一部分,以及可以在任何类型的对象上调用的operator<<
在该层次结构内。让C ++运行时多态性和函数覆盖的魔力为您完成所有这些,因此main
不需要知道A
或B
之间的差异或每个成员变量的成员变量,也不知道每个指针实际指向哪种对象。
您还应该存储智能指针以避免内存泄漏。
#include <iostream>
#include <vector>
#include <memory>
struct Super {
int A;
Super(int a) : A(a) {}
virtual void foo() = 0;
virtual void print(std::ostream& os) const
{
os << "A: " << A << '\n';
};
};
struct Sub : Super {
int B;
Sub(int a, int b) : Super(a), B(b) {}
void foo() { std::cout << "calling foo from Sub\n"; }
virtual void print(std::ostream& os) const
{
Super::print(os);
os << "B: " << B << '\n';
}
};
std::ostream& operator<<(std::ostream& os, const Super& obj)
{
obj.print(os);
return os;
}
int main()
{
std::vector<std::unique_ptr<Super>> vec;
vec.emplace_back(std::make_unique<Sub>(2, 3));
vec[0]->foo();
std::cout << *(vec[0]);
}