是否可以使用指向基类的指针来访问派生类的成员?
// Example program
#include <iostream>
#include <vector>
#include <memory>
#include <string>
class A {
public:
std::string x = "this is the wrong x\n";
};
template <class T>
class B : public A {
public:
T x;
};
int main()
{
std::vector<std::unique_ptr<A>> vector;
auto i = std::make_unique<B<int>>();
i->x = 6;
vector.push_back(std::move(i));
for(auto &element : vector){
std::cout << element->x;
}
}
在这里,我总是从类A获得输出。我无法进行类型转换,因为我事先不知道该元素是A类型还是B类型。有适当的方法做到这一点吗?
答案 0 :(得分:2)
正确的方法是制作一个virtual
函数来执行类似打印的任务。
class A {
public:
std::string x = "this is the wrong x\n";
virtual ~A() = default;
virtual void print() const { std::cout << x; }
};
template <class T>
class B : public A {
public:
T x;
virtual void print() const override { std::cout << x; }
};
int main()
{
std::vector<std::unique_ptr<A>> vector;
auto i = std::make_unique<B<int>>();
i->x = 6;
vector.push_back(std::move(i));
for(auto &element : vector){
element->print();
}
}
答案 1 :(得分:0)
如果您有一个指向基类的指针,则只能访问在该基类上定义的内容(不进行类型转换)。就编译器所知,它是基类的实例,而没有。
多态行为涉及使用virtual
函数-派生类可以更改在调用基类的virtual
函数时调用哪个函数。请注意,该机制对于成员不存在(关于成员您将作哪些更改?只有类型,而在派生类中进行更改则毫无意义)。因此,使用指向应该具有自定义行为的基类的指针,唯一有意义的事情就是调用其虚拟函数。
现在,您可能会认为“好吧,我将通过虚拟函数访问x
”,但是这里的问题是,当您在虚拟机中声明虚拟函数时,必须指定所涉及的类型。基类已经。这是有道理的:编译器需要知道函数涉及哪些类型,甚至是虚函数。如果它们是“兼容的”,则只能在覆盖函数中传递和返回不同的类型-有关更多信息,请参见covariance and contravariance。
因此,除非您所有的T
是协变的,否则虚函数也无法帮助您。
此概念的核心缺陷是,您希望非模板化函数中具有某种类型(即element->x
)取决于某些对象(例如element
)的动态类型。这是不可能的,因为编译器必须在编译时知道每个表达式的类型。因此,您必须以不同的方式处理问题。