2012-01-18 175 views
1

如何通过基类对象访问派生类的函数? 我已编译并运行该程序没有任何错误(vs2010 express版)。 任何人都可以澄清这个话题吗?派生类访问的基类 - 如何?

#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; 
} 

- >输出

f2 5 // which concept is supports this output? 

回答

1

你要做的就是C风格的上溯造型这导致undefined对象内容 - 考虑到它不被推荐与C++一起使用,因为我们有更好的工具可用。请看看static_cast <>和dynamic_cast <> - 他们会确保你的演员将工作。作为例子,如果你会做

B * b = dynamic_cast<B*>(aaa); 

你甚至不能够编译它,因为A是不多态性,即使是和类不匹配,则返回NULL,而不是“东西未定义”。

请注意,动态转换比static_cast或C风格转换(其行为或多或少像static_casts)贵一点 - 但由于它们的定义行为,您可能会考虑至少在调试版本中使用这些转换:

#ifdef _DEBUG 
    assert(dynamic_cast<B*>(aaa)); 
#endif 

这可以防止a)upcasts和b)由于未定义的行为(我假设您使用调试版本进行测试)导致的运行时错误。

+1

谢谢Coder02,我知道有各种铸造关键字为C++,但我从来没有想过,我是执行C风格的类型转换。 谢谢大家的回复。这是一个很好的帮助:) – fadedreamz 2012-01-18 19:34:09

+0

不要让这个错误 - C风格的转换并不总是很糟糕,并不总是导致C++中的未定义结果 - 它只是在你的情况下,因为A不会继承B. @ Anders已经回复了这在内存中的样子,以及为什么结果在这种情况下是未定义的。 – Coder02 2012-01-19 07:06:09

1

这是不确定的行为(即它的工作原理是意外)。

1

考虑这个问题:

struct A 
{ 
    int i; 
    short s; 
}; 

struct B : A 
{ 
    long p; 
}; 

struct A a; 

+-----+-----+ 
| i | s | 
+-----+-----+ 

struct B* b = (B*)&a; 

现在访问结构成员磷; (b->p)

你认为p值有效是否合理?它仍然指向'a'实例。

你应该看看dynamic_cast和虚函数

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

的编译实际治疗B-> 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是一个实例,该行为将是不确定的(如果是刚刚一个int成员,而不是X,它应该显示。)

相关问题