关于指针向下转换/继承

时间:2010-07-19 20:11:40

标签: c++

所以我要完成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属性和方法。换句话说,这里没有任何失败。任何人都可以给我一个例子或在代码中添加一些内容,这些内容会清楚地向我展示如何为派生分配基础可以搞砸了吗?

3 个答案:

答案 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演员。总是!