此程序运行没有任何异常。你能解释为什么动态演员和静态演员会成功吗?以及C ++如何设法解决所需的虚函数?
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;
}
答案 0 :(得分:4)
让我们从为什么它没有抛出任何异常开始,因为它非常简单:dynamic_cast
在您尝试转换引用类型时抛出异常,但它失败了。在指针上使用dynamic_cast
时,如果成功则返回指针,如果指针失败则返回空指针。
至于为什么你从未收到失败的演员表,你的所有dynamic_cast
都 up 层次结构,以产生Shape *
。由于所有有问题的对象都是派生自Shape
,因此这将始终成功 - 事实上,转换可以隐式完成。
为了演示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;
}
这次我们使用dynamic_cast从Shape *
到Square *
或Circle *
。当且仅当指针对象的动态类型是该类型时,这将成功。否则它将产生一个空指针。当且仅当我们得到一个非空指针时,我们才调用该特定类型的成员函数。
总结:如果有对派生对象的指针/引用,则可以隐式转换为指向基类的指针。你不需要dynamic_cast
(或任何明确的演员表),因为这总是安全的。
当您从指针/引用转换为base以获取指向派生的指针/引用时,然后通常需要使用dynamic_cast
。这将基于指针对象的实际类型(即,动态类型)是否是期望目标(或其基础)而成功/失败。在这种情况下,根据您是使用指针还是引用,失败的信号会有所不同。作为参考,失败将引发异常。对于指针,失败将产生空指针。
答案 1 :(得分:3)
为什么要这样? dynamic_cast
如果转换失败则返回NULL
,它不会为指针抛出异常。
另外,除此之外,它为什么要失败? Square
和Circle
都是Shape
。演员阵容很好。
由于基本的多态性,输出正如您所见。您有Shape*
指向Square
对象或Circle
对象。 virutal
函数调用从最派生的类调用overriden方法。这是OOP的核心方面。
在大多数实现中,这是通过virtual function tables
实现的。虽然您有一个Shape*
,但该对象包含一个指向内部虚拟函数表的指针。由于该成员在演员表期间不会更改,因此它指向Square
或Circle
的虚拟功能表,因此可以正确解析调用。
答案 2 :(得分:1)
您正在使用dynamic_cast
从派生类型转换为基本类型,并且没有歧义。你为什么期望失败?此外,在指针上使用dynamic_cast
不会抛出异常(而是返回NULL
)。在类型引用之间进行转换时,它可能会抛出异常。
由于构建简单类的方式,static_cast
成功了。由于CircleFunction()
和SquareFunction()
实际上并没有尝试访问任何无效的类成员变量,因此程序能够成功运行(幸运的是),使用static_cast
在类型之间错误地转换不是你应该做的事情。
答案 3 :(得分:0)
简短回答:当您在Circle指针上执行static_cast<Square>
并在Square指针上执行static_cast<Circle>
时,您已经进入未定义行为。几乎任何事情都可能发生在那一点上。
此外,当您调用dynamic_cast
时,如果您正在转换为指针,它可能会失败并返回NULL。如果您要转换为引用,它只会抛出异常。此外,编译器可以选择用编译时替换dynamic_cast,如果它在编译时知道没有歧义(这是这种情况,因为你是从child-&gt; parent转换)。
你得到的输出是因为这些类彼此相似,但是当演员表不合法时,他们仍设法工作。鉴于未定义的行为,如果您继续进行更改,则无法依赖它。