所以我要完成prata的C ++入门,我就是RTTI。他展示了一系列向下倾斜,只是说这是错的,但我希望看到一个更好的例子。
class Grand
{
private:
int hold;
public:
Grand(int h=0) : hold(h) {}
virtual void Speak() const { cout << "I am a grand class\n";}
virtual int Value() const {return hold; }
void Gah() const {cout << "ok" << endl;}
};
class Superb : public Grand
{
public:
Superb(int h = 0) : Grand(h){}
void Speak() const {cout << "I am a superb class!!\n";}
virtual void Say() const
{ cout << "I hold the superb value of " << Value() << "!\n";}
void Sah() const { cout << "Noak" << endl;}
};
class Magnificent : public Superb
{
private:
char ch;
public:
int hour;
Magnificent(int h = 0, char c = 'A') : Superb (h), ch(c){}
void Speak() const {cout << "I am a magnificent class!!!\n";}
void Say() const {cout << "I hold the character " << ch <<
"and the integer " << Value() << "!\n";}
void Mah() const {cout << "Ok" << endl;}
};
Grand * GetOne();
int _tmain(int argc, _TCHAR* argv[])
{
/*
srand(time(0));
Grand * pg;
Superb * ps;
*/
Grand * pg = new Grand;
Grand * ps = new Superb;
Grand * pm = new Magnificent;
Magnificent * ps2 = (Magnificent *)pg;
ps2->Gah();
cout << ps2->hour << endl;
system("pause");
}
所以上面,我正在为一个派生的基础构建一个总体上没有完成的基础。但是,在这个例子中,我真正受限于什么?当我投射pg时,我仍然可以通过ps2访问所有的grand / superb / grand属性和方法。换句话说,这里没有任何失败。任何人都可以给我一个例子或在代码中添加一些内容,这些内容会清楚地向我展示如何为派生分配基础可以搞砸了吗?
答案 0 :(得分:2)
不要使用C风格的演员阵容 他们不安全。 C ++引入了4个新的强制转换,你正在寻找的是dynamic_cast&lt;&gt;
Magnificent * ps2 = dynamic_cast<Magnificent*>(pg); // If pg is a Magnificent
// (or is a super class of
// Magnificent) it works fine.
// If pg is not a Magnificent (in this case) it will return NULL.
当您使用C样式转换时,您告诉编译器忽略所有规则并执行您告诉它的操作(编译器很乐意这样做)。没有做任何检查以确保你正在做什么是有意义的。
C ++样式转换更具限制性,每个转换都具有特定的转换范围。 dynamic_cast用于强制转换类层次结构。
答案 1 :(得分:0)
只需将值设置为ps2->hour
,就会超出内存 - ps2的分配足以容纳Grand
实例,这对于Magnificent
实例来说是不够的(如它有更多的类变量。)
尝试此实验:
- 分配一组Grand
个对象
- 将hold
的值设置为某事物
- 通过强制转换,将hour
的值设置为另一个值
- 为所有元素打印hold
的值
- 看看会发生什么......
答案 2 :(得分:0)
一旦调用实际使用派生类的数据成员的派生类实现的虚方法,它就会中断。现在你很幸运 - Gah
成员函数不接触任何数据。
这是一个真正失败的例子,展示了C ++中C风格演员的危险:
struct base
{
virtual ~base() {}
virtual void print() const { std::cout << "base" << std::endl; }
};
struct second_base // :)
{
virtual ~second_base() {}
virtual void second_print() const { std::cout << second << std::endl;
};
class derived: second_base, public base
{
std::string name_;
public:
explicit derived( const std::string& n ) : name_( n ) {}
virtual void print() const
{
std::cout << "derived: " << name_ << std::endl;
}
};
base* pbase( new base );
derived* pderived = ( derived* )pbase; // C-cast will allow this
pderived->print(); // BOOM!
处理此问题的RTTI方法是dynamic_cast
,当您尝试转换为错误的子类时会返回0
:
base* pbad( new base );
base* pgood( new derived( "humppa" ));
derived* pfails( dynamic_cast<derived*>( pbad ));
derived* pworks( dynamic_cast<derived*>( pgood ));
if ( pfails ) pfails->print(); // no cookie
if ( pworks ) pworks->print(); // prints "derived: humppa"
研究C++ casts并使用它们代替C演员。总是!