如何通过基类对象访问派生类的函数? 我编译并运行程序没有任何错误(vs2010 express edition)。 任何人都可以澄清这个话题吗?
#include <iostream>
using namespace std;
class A {
public:
void f1() { cout << " f1 \n"; }
};
class B : public A{
int x;
public:
void f2(int x) {this->x = x; cout << "f2 " << this->x <<"\n";}
};
int main(int argc, char * argv[])
{
A * aaa = new A(); // created a base instance
B * b = (B *) aaa; // typecasted it to derived class
b->f2(5); // try to access function, which should not be possible (run-time error?)
return 0;
}
- &GT;输出
f2 5 // which concept is supports this output?
答案 0 :(得分:3)
这是不可能的,因为没有这样的方法。您刚刚调用了 undefined 行为,而您的编译器正在对您进行欺骗。
让我们玩游戏来见证这个in action:
#include <iostream>
struct A {
A(int i = 0): value(i) {}
int value;
};
struct B: A {
B(int i): A(0), other(i) {}
void set(int i) { other = i; }
int other;
};
int main(int argc, char* argv[]) {
A* a = new A[2];
B* b = (B*)a;
b->set(argc);
std::cout << a->value << " " << (a+1)->value << "\n";
std::cout << b->value << " " << b->other << "\n";
}
输出:
0 1
0 1
哦!为什么数组中的第二个A
发生了变化?
你已经骗了编译器,它骗了你......程序写了它应该没有的地方。
答案 1 :(得分:1)
这是未定义的行为(即它偶然起作用)。
答案 2 :(得分:1)
考虑一下:
struct A
{
int i;
short s;
};
struct B : A
{
long p;
};
struct A a;
+-----+-----+
| i | s |
+-----+-----+
struct B* b = (B*)&a;
现在访问struct member p; (b->p)
你觉得p有效值似乎是合理的吗?它仍然指向'a'实例。
你应该看一下dynamic_cast和虚函数
答案 3 :(得分:1)
编译实际上将b-&gt; f2视为f2(b) 和f2(b)等于(伪代码)
address_of_x = b+offset_x_in_B
int x;
memcpy(&x, address_of_x, sizeof(int));
std::cout<<x<<std::endl;
其中offset_x_in_B是编译器确定的c ++对象模型的值。
因此,当b是A实例时,行为将是未定义的(如果A只有一个int成员,而不是x,则应该显示它。)
答案 4 :(得分:1)
你做的是C风格的 upcast ,导致未定义的对象内容 - 考虑不建议将它与C ++一起使用,因为我们有更好的工具在那里。请查看static_cast&lt;&gt;和dynamic_cast&lt;&gt; - 他们会确保你的演员阵容能够奏效。例如,如果你已经完成了
B * b = dynamic_cast<B*>(aaa);
你甚至无法编译它,因为A不是多态的,即使它和类不匹配,它也会返回NULL而不是“未定义的东西”。
请注意,动态转换比static_cast或C风格的转换(它的行为或多或少类似于static_casts)要贵一些 - 但由于它们的定义行为,您可能会考虑至少在调试版本中使用这些:
#ifdef _DEBUG
assert(dynamic_cast<B*>(aaa));
#endif
这可以防止a)upcast和b)由于未定义的行为导致的运行时错误(我假设您使用调试版本进行测试)。