C风格投射到相同的层次水平

van*_*yen 0 c++ casting

我有以下代码段:

#include <iostream>

using namespace std;

class IA 
{
    public:
    virtual void printA() = 0;
    virtual ~IA(){};
};

class IB 
{
    public:
    virtual void printB() = 0;
    virtual ~IB(){}
};

class IC : public IA, public IB 
{
    public:
    void printA() {cout << "hello world a" << endl; }
    void printB() {cout << "hello world b" << endl; }
};

void func(IB* p)
{
    p->printB();
}

int main()
{
    IA* p = new IC;
    p->printA();
    cout << "cast to ib" << endl;
    func((IB*)p);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在我执行代码后,我得到以下结果:

hello world a  
cast to ib 
hello world a
Run Code Online (Sandbox Code Playgroud)

我的问题是,编译器做什么(IB*)p导致func调用p->printB()但得到结果hello a而不是hello b?

演员幕后的幕后故事是什么?编译生成什么用于转换?如果我改变func(dynamic_cast<IB*>(p)),它得到的print b是正确的结果.

Max*_*kin 5

(IB*)p这里没有reinterpret_cast<IB*>(p),但是,产生了无效的指针,因为IA并IB没有关系.

dynamic_cast<IB*>(p)做正确的事,因为它会检查的所属类别为对象*p,发现对象派生既IA和IB,并返回一个适当调整指针IB的子对象IC.请注意,IA指针与指向对象的指针重合IC,不同于IB:

struct IA {
    virtual ~IA(){};
};

struct IB {
    virtual ~IB(){}
};

struct IC : IA, IB {};

int main() {
    IA* p = new IC;
    std::cout << "IA: " << p << '\n';
    std::cout << "IB: " << dynamic_cast<IB*>(p) << '\n';
    std::cout << "IC: " << dynamic_cast<IC*>(p) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

输出:

IA: 0x21c1c20
IB: 0x21c1c28
IC: 0x21c1c20
Run Code Online (Sandbox Code Playgroud)

C语言转换在C++中如何工作的完整信息:显式类型转换:

遇到C样式的强制转换表达式时,编译器会尝试按以下顺序将其解释为以下强制转换表达式:

  1. const_cast<new_type>(expression);
  2. static_cast<new_type>(expression),使用扩展:指向或派生类的引用另外允许转换为指针或引用到明确的基类(反之亦然),即使基类是不可访问的(即,此转换忽略了私有继承说明符).同样适用于将指向成员的指针转换为指向明确的非虚拟基础成员的指针;
  3. static_cast(带扩展名)后跟const_cast;
  4. reinterpret_cast<new_type>(expression);
  5. reinterpret_cast接着是const_cast.即使无法编译,也选择满足相应铸造操作员要求的第一选择.如果可以以多种方式将强制转换解释为static_cast,后跟const_cast,则无法对其进行编译.此外,允许C样式强制转换表示法从指针转换为指向不完整类类型的指针.如果两个expression和new_type都指向不完全类类型,它是不确定是否static_cast还是reinterpret_cast被选中.

请注意,C风格的情况永远不会dynamic_cast.

C风格的强制转换在C++中被认为是不好的做法,因为当类型和层次结构发生变化时,它们的含义会无声地改变.使用C++强制转换来获得健壮的代码.