C++ 动态强制转换和静态强制转换的奇怪行为
这个程序毫无例外地运行。你能解释一下为什么动态强制转换和静态强制转换是成功的吗?以及C++如何解决所需的虚拟函数?C++ 动态强制转换和静态强制转换的奇怪行为,c++,oop,casting,virtual-functions,dynamic-cast,C++,Oop,Casting,Virtual Functions,Dynamic Cast,这个程序毫无例外地运行。你能解释一下为什么动态强制转换和静态强制转换是成功的吗?以及C++如何解决所需的虚拟函数? class Shape { private : string helperFunction(); public : virtual void draw() = 0; virtual void type(); }; void Shape::type() { cout <<
class Shape
{
private :
string helperFunction();
public :
virtual void draw() = 0;
virtual void type();
};
void Shape::type()
{
cout << "Shape Type";
}
// ----------------------------------------------------------------------------
class Circle : public Shape
{
private:
string circlething;
public :
virtual void draw();
virtual void type();
void CircleFunction();
};
void Circle::draw()
{
cout <<"Circle Draw" << endl;
}
void Circle::type()
{
cout <<"Circle Type" << endl;
}
void Circle::CircleFunction()
{
circlething = "Circle Thing";
cout << circlething;
cout << "Circle Function" << endl;
}
class Square : public Shape
{
private :
string squarething;
public :
virtual void draw();
virtual void type();
void SquareFunction();
};
void Square::draw()
{
cout <<"Square Draw" << endl;
}
void Square::type()
{
cout <<"Square Type" << endl;
}
void Square::SquareFunction()
{
squarething = "Square Thing";
cout << squarething;
cout << "Square Function" << endl;
}
// ----------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
vector<Shape *> shapes;
Circle circle;
Square square;
shapes.push_back(&circle);
shapes.push_back(&square);
vector<Shape *>::const_iterator i;
for (i = shapes.begin(); i < shapes.end(); ++i)
{
cout << "\n*** Simple Type ***\n" << endl;
(*i)->type();
(*i)->draw();
cout << "---Static Cast Circle--" << endl;
Circle* circle = static_cast<Circle*>(*i);
circle->type();
circle->draw();
circle->CircleFunction();
cout << "---Static Cast Square--" << endl;
Square* square = static_cast<Square*>(*i);
square->type();
square->draw();
square->SquareFunction();
cout << "---Static Cast Circle to Shape --" << endl;
Shape* shape1 = static_cast<Shape*> (circle);
shape1->type();
shape1->draw();
cout << "--- Dynamic Cast Circle to Shape --" << endl;
Shape* shape2 = dynamic_cast<Shape*> (circle);
shape2->type();
shape2->draw();
cout << "--- Static Cast Square to Shape --" << endl;
Shape* shape3 = static_cast<Shape*> (square);
shape3->type();
shape3->draw();
cout << "--- Dynamic Cast Square to Shape --" << endl;
Shape* shape4 = dynamic_cast<Shape*> (square);
shape4->type();
shape4->draw();
}
int x;
cin >> x;
return 0;
}
类形状
{
私人:
字符串helperFunction();
公众:
虚空绘制()=0;
虚空类型();
};
空心形状::类型()
{
cout为什么要这样做?dynamic_cast
返回NULL
如果强制转换失败,它不会为指针抛出异常
另外,撇开这一点不谈,为什么它会失败呢?正方形
和圆形
都是形状
s。所以演员阵容很好
由于基本多态性,输出与您看到的一样。您有一个形状*
,它指向正方形
对象或圆形
对象。virutal
函数调用来自最派生类的重写方法。这是OOP的一个中心方面
在大多数实现中,这是通过虚拟函数表
实现的。尽管您有一个形状*
,但对象内部有一个指向虚拟函数表的指针。因为该成员在强制转换过程中没有改变,所以它指向正方形
或圆形
的虚拟函数表,因此调用正确解决了这些问题
让我们从它为什么不抛出任何异常开始,因为它非常简单:dynamic\u cast
在您尝试抛出引用类型时抛出异常,但失败。当您对指针使用dynamic\u cast
时,如果成功,它将返回指针,如果失败,它将返回空指针
至于为什么您从未获得失败的强制转换,您的所有动态\u强制转换
都在层次结构上,以生成一个形状*
。由于所有有问题的对象都是从形状
派生的,因此这将总是成功的——事实上,转换可以隐式完成
为了演示dynamic_cast
的真正意图,让我们编写一些稍微不同的代码:
#include <iostream>
#include <vector>
using namespace std;
class Shape {
public :
virtual void draw() = 0;
};
class Circle : public Shape
{
public :
virtual void draw() { cout << "Circle Draw\n"; }
void circlefunc() { cout << "circle func\n"; }
};
class Square : public Shape
{
public :
virtual void draw() { cout << "Square Draw\n"; }
void squarefunc() { cout << "Square Func\n"; }
};
int main() {
vector<Shape *> shapes;
Circle circle;
Square square;
shapes.push_back(&circle); // implicit conversion from Circle * to Shape *
shapes.push_back(&square); // implicit conversion from Square * to Shape *
Circle *c;
Square *s;
for (int i=0; i<shapes.size(); i++) {
shapes[i]->draw(); // draw polymorphically
if (c = dynamic_cast<Circle *>(shapes[i])) // try to cast to Circle *
c->circlefunc(); // if it worked, invoke circlefunc
else if (s = dynamic_cast<Square *>(shapes[i])) // likewise for square
s->squarefunc();
}
return 0;
}
#包括
#包括
使用名称空间std;
阶级形态{
公众:
虚空绘制()=0;
};
班级圈子:公共形态
{
公众:
virtual void draw(){cout您正在使用dynamic\u cast
将派生类型转换为基类型,并且没有任何歧义。为什么您希望失败?另外,在指针上使用dynamic\u cast
不会引发异常(相反,它将返回NULL
)。在类型引用之间强制转换时,它可能引发异常
由于简单类的构造方式,您的static\u cast
是成功的。由于CircleFunction()
和SquareFunction()
实际上没有尝试访问任何无效的类成员变量,因此程序能够成功运行(幸运的是),使用static\u cast
在类型之间错误地转换不是你应该做的事情。简短回答:当你在圆指针上执行static\u cast
和在方指针上执行static\u cast
时,你已经陷入了未定义的行为。几乎任何事情都可能发生在这一点上
此外,当您调用dynamic_cast
时,如果您对指针进行强制转换,它可能会失败并返回NULL。它仅在您转换为引用时才会引发异常。此外,如果编译器在编译时知道不存在歧义,则可以选择用编译时强制转换替换dynamic_cast(这里就是这种情况,因为您是从child->parent进行施法的)
您得到的输出是因为这些类彼此非常相似,虽然强制转换是不合法的,但它们无论如何都能工作。鉴于未定义的行为,如果您继续进行更改,就不可能依赖于此。请注意,OP在中插入了一个圆*
和一个正方形*
ctor
,然后在迭代时将圆同时转换为正方形*
和圆形*
。因此OP将圆转换为正方形(通过共享形状基)你能解释一下为什么静态强制转换也会成功吗?@kunj2aan:static\u cast
甚至不会试图判断你尝试的转换是否有效。在你的情况下,它可能会起作用,主要是因为你的成员函数不使用任何类数据,所以用指向它的指针调用它们错误的数据不会造成明显的伤害/问题。嗨,我用新的成员函数修改了代码,程序仍然可以正常运行。这就是你的意思吗?