C++ static_cast 和 dynamic_cast 的多态 类 使用 unique_ptr
C++ static_cast and dynamic_cast of polymorphic classes using unique_ptr
我在 C++ 中练习 static_cast 和 dynamic_cast 多态 类。我尝试使用原始指针和 unique_ptr。虽然前者不会产生问题,但后者会产生问题。在这里我展示我的代码:-
#include <iostream>
#include <memory>
#include <exception>
#include <stdexcept>
using namespace std;
class A
{
int a, id=0;
static int i;
public:
A()
{
id=++i;
cout<<"constructing A: "<<id<<"\n";
}
virtual void get()
{
cout<<"enter a: ";
cin>>a;
}
virtual void disp()
{
cout<<"a = "<<a<<"\n";
}
virtual ~A()
{
cout<<"destroying A: "<<id<<"\n";
}
};
int A::i=0;
class B: public A
{
int b;
public:
B()
{
cout<<"constructing B\n";
}
void get()
{
cout<<"enter b: ";
cin>>b;
}
void disp()
{
cout<<"b = "<<b<<"\n";
}
~B()
{
cout<<"destroying B\n";
}
};
void show (unique_ptr<B> &p)
{
p->get();
p->disp();
}
void d_cast (unique_ptr<A> &pa)
{
unique_ptr<B> pb;
try
{
pb.reset(dynamic_cast<B*>(pa.release()));
if (pb==nullptr)
throw runtime_error {"nullptr exception"};
show(pb);
cout<<"dynamic_cast successful\n\n";
}
catch (exception &e)
{
cout<<"dynamic_cast unsuccessful: "<<e.what()<<"\n\n";
}
pa.reset(pb.release());
}
void s_cast (unique_ptr<A> &pa)
{
unique_ptr<B> pb;
try
{
pb.reset(static_cast<B*>(pa.release()));
if (pb==nullptr)
throw runtime_error {"nullptr exception"};
show(pb);
cout<<"static_cast successful\n\n";
}
catch (exception &e)
{
cout<<"static_cast unsuccessful: "<<e.what()<<"\n\n";
}
pa.reset(pb.release());
}
int main()
{
cout<<R"(using "unique_ptr<A> pa with new A" :-)"<<"\n\n";
unique_ptr<A> pa(new A); // (1)
d_cast(pa);
s_cast(pa); // (2)
cout<<"\n"<<R"(using "unique_ptr<A> pa with new B" :-)"<<"\n\n";
pa.reset(new B);
d_cast(pa);
s_cast(pa);
return 0;
}
代码的输出是:-
using "unique_ptr<A> pa with new A" :-
constructing A: 1
dynamic_cast unsuccessful: nullptr exception
static_cast unsuccessful: nullptr exception
using "unique_ptr<A> pa with new B" :-
constructing A: 2
constructing B
enter b: 7
b = 7
dynamic_cast successful
enter b: 8
b = 8
static_cast successful
destroying B
destroying A: 2
我已经标记了两个问题:-
为什么第一个对象{表示为 (1)} 没有被销毁,而用 "new B" 调用的对象被销毁了?
为什么 (2) 抛出异常?有趣的是,如果我颠倒 s_cast(pa)
和 d_cast(pa)
的定位,那么 (2) 不会抛出任何异常并且工作正常(但是问题 (1) 仍然存在)。
好的!所以你需要像这样改变你的函数 d_cast
函数定义:-
void d_cast (unique_ptr<A> &pa)
{
unique_ptr<B> pb;
A *aptr=pa.release(); // make a pointer of type A
try
{
pb.reset(dynamic_cast<B*>(aptr)); // assign aptr instead of pa.release() here
if (pb==nullptr)
throw runtime_error {"nullptr exception"};
show(pb);
cout<<"dynamic_cast successful\n\n";
pa.reset(pb.release()); // reset pa with pb.release() and not with aptr becomes pb has the ownership of aptr
}
catch (exception &e)
{
cout<<"dynamic_cast unsuccessful: "<<e.what()<<"\n\n";
pa.reset(aptr); // reset aptr back to pa as pb holds no ownership of aptr
}
}
您一定知道 d_cast
会失败,因此 dynamic_cast<B*>(pointer_of_type_A)
的表达式会 return nullptr
。如果存在引用而不是指针,则将抛出 std::bad_cast
异常。但是因为你使用的是release()
函数,所以unique_ptr对象pa
摆脱了指针的所有权,没有对象或指针可以追溯。因此,如果转换失败,您应该使用 A *aptr
来保存释放的指针,并 return 它到 pa
。
如果你这样做,你的两个问题都解决了
我在 C++ 中练习 static_cast 和 dynamic_cast 多态 类。我尝试使用原始指针和 unique_ptr。虽然前者不会产生问题,但后者会产生问题。在这里我展示我的代码:-
#include <iostream>
#include <memory>
#include <exception>
#include <stdexcept>
using namespace std;
class A
{
int a, id=0;
static int i;
public:
A()
{
id=++i;
cout<<"constructing A: "<<id<<"\n";
}
virtual void get()
{
cout<<"enter a: ";
cin>>a;
}
virtual void disp()
{
cout<<"a = "<<a<<"\n";
}
virtual ~A()
{
cout<<"destroying A: "<<id<<"\n";
}
};
int A::i=0;
class B: public A
{
int b;
public:
B()
{
cout<<"constructing B\n";
}
void get()
{
cout<<"enter b: ";
cin>>b;
}
void disp()
{
cout<<"b = "<<b<<"\n";
}
~B()
{
cout<<"destroying B\n";
}
};
void show (unique_ptr<B> &p)
{
p->get();
p->disp();
}
void d_cast (unique_ptr<A> &pa)
{
unique_ptr<B> pb;
try
{
pb.reset(dynamic_cast<B*>(pa.release()));
if (pb==nullptr)
throw runtime_error {"nullptr exception"};
show(pb);
cout<<"dynamic_cast successful\n\n";
}
catch (exception &e)
{
cout<<"dynamic_cast unsuccessful: "<<e.what()<<"\n\n";
}
pa.reset(pb.release());
}
void s_cast (unique_ptr<A> &pa)
{
unique_ptr<B> pb;
try
{
pb.reset(static_cast<B*>(pa.release()));
if (pb==nullptr)
throw runtime_error {"nullptr exception"};
show(pb);
cout<<"static_cast successful\n\n";
}
catch (exception &e)
{
cout<<"static_cast unsuccessful: "<<e.what()<<"\n\n";
}
pa.reset(pb.release());
}
int main()
{
cout<<R"(using "unique_ptr<A> pa with new A" :-)"<<"\n\n";
unique_ptr<A> pa(new A); // (1)
d_cast(pa);
s_cast(pa); // (2)
cout<<"\n"<<R"(using "unique_ptr<A> pa with new B" :-)"<<"\n\n";
pa.reset(new B);
d_cast(pa);
s_cast(pa);
return 0;
}
代码的输出是:-
using "unique_ptr<A> pa with new A" :-
constructing A: 1
dynamic_cast unsuccessful: nullptr exception
static_cast unsuccessful: nullptr exception
using "unique_ptr<A> pa with new B" :-
constructing A: 2
constructing B
enter b: 7
b = 7
dynamic_cast successful
enter b: 8
b = 8
static_cast successful
destroying B
destroying A: 2
我已经标记了两个问题:-
为什么第一个对象{表示为 (1)} 没有被销毁,而用 "new B" 调用的对象被销毁了?
为什么 (2) 抛出异常?有趣的是,如果我颠倒
s_cast(pa)
和d_cast(pa)
的定位,那么 (2) 不会抛出任何异常并且工作正常(但是问题 (1) 仍然存在)。
好的!所以你需要像这样改变你的函数 d_cast
函数定义:-
void d_cast (unique_ptr<A> &pa)
{
unique_ptr<B> pb;
A *aptr=pa.release(); // make a pointer of type A
try
{
pb.reset(dynamic_cast<B*>(aptr)); // assign aptr instead of pa.release() here
if (pb==nullptr)
throw runtime_error {"nullptr exception"};
show(pb);
cout<<"dynamic_cast successful\n\n";
pa.reset(pb.release()); // reset pa with pb.release() and not with aptr becomes pb has the ownership of aptr
}
catch (exception &e)
{
cout<<"dynamic_cast unsuccessful: "<<e.what()<<"\n\n";
pa.reset(aptr); // reset aptr back to pa as pb holds no ownership of aptr
}
}
您一定知道 d_cast
会失败,因此 dynamic_cast<B*>(pointer_of_type_A)
的表达式会 return nullptr
。如果存在引用而不是指针,则将抛出 std::bad_cast
异常。但是因为你使用的是release()
函数,所以unique_ptr对象pa
摆脱了指针的所有权,没有对象或指针可以追溯。因此,如果转换失败,您应该使用 A *aptr
来保存释放的指针,并 return 它到 pa
。
如果你这样做,你的两个问题都解决了