C++类型转换dynamic_pointer_cast,报错undefined reference to `typeinfo for BaseMsg‘

具体问题:

在使用dynamic_pointer_cast由基类转换子类时,编译报错

报错:

/usr/bin/ld: CMakeFiles/sunnet.dir/src/Service.cpp.o: warning: relocation against `_ZTI7BaseMsg' in read-only section `.text._ZSt20dynamic_pointer_castI10ServiceMsg7BaseMsgESt10shared_ptrIT_ERKS2_IT0_E[_ZSt20dynamic_pointer_castI10ServiceMsg7BaseMsgESt10shared_ptrIT_ERKS2_IT0_E]'
/usr/bin/ld: CMakeFiles/sunnet.dir/src/Service.cpp.o: in function `std::shared_ptr<ServiceMsg> std::dynamic_pointer_cast<ServiceMsg, BaseMsg>(std::shared_ptr<BaseMsg> const&)':
Service.cpp:(.text._ZSt20dynamic_pointer_castI10ServiceMsg7BaseMsgESt10shared_ptrIT_ERKS2_IT0_E[_ZSt20dynamic_pointer_castI10ServiceMsg7BaseMsgESt10shared_ptrIT_ERKS2_IT0_E]+0x34): undefined reference to `typeinfo for BaseMsg'
/usr/bin/ld: CMakeFiles/sunnet.dir/src/Service.cpp.o: in function `ServiceMsg::ServiceMsg()':
Service.cpp:(.text._ZN10ServiceMsgC2Ev[_ZN10ServiceMsgC5Ev]+0x18): undefined reference to `BaseMsg::BaseMsg()'
/usr/bin/ld: CMakeFiles/sunnet.dir/src/Service.cpp.o: in function `ServiceMsg::~ServiceMsg()':
Service.cpp:(.text._ZN10ServiceMsgD2Ev[_ZN10ServiceMsgD5Ev]+0x38): undefined reference to `BaseMsg::~BaseMsg()'
/usr/bin/ld: CMakeFiles/sunnet.dir/src/Service.cpp.o:(.data.rel.ro._ZTI10ServiceMsg[_ZTI10ServiceMsg]+0x10): undefined reference to `typeinfo for BaseMsg'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/sunnet.dir/build.make:145: sunnet] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/sunnet.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

相关代码:

//消息基类
class BaseMsg
{
public:
    enum Type {
        //消息类型
        SERVICE = 1
    };
    //消息类型
    uint8_t type;
    //用于检测内存泄漏,仅用于调试
    char load[999999]{};
public:
    BaseMsg();
    virtual ~BaseMsg();
};


//服务间消息
class ServiceMsg:public BaseMsg{
public:
    uint32_t source;    //消息发送方
    shared_ptr<char> buff;  //消息内容
    size_t size;        //消息内容大小
};

 类型转化:

auto m = dynamic_pointer_cast<ServiceMsg>(msg);     //dynamic_pointer_cast 强制类型转换

解决方法:

在基类的构造函数和析构函数后加上 {}

    BaseMsg(){};
    virtual ~BaseMsg(){};

编译通过

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、下载须知: .................本书无目录 .................本书经过内容识别处理,所以好处就是书上的案例源码可以直接粘贴复制到编辑器中,当然有个别括号什么的可能需要自己纠正一下。 ................本书高清 ...............本书是和代码结合在一起讲解的,其中也讲到了运行时类的识别等等。 二、截取部分章节 《第18章:运行时类型识别》 RTTI的两种使用方法 使用RT T I有两种不同的方法。第一种就像s i z e o f ( ),因为它看上就像一个函数。但实际上它是 由编译器实现的。t y p e i d ( )带有一个参数,它可以是一个对象引用或指针,返回全局t y p e i n f o类的 常量对象的一个引用。可以用运算符“= =”和“!=”来互相比较这些对象。也可以用n a m e ( )来 获得类型的名称。注意,如果给t y p e i d ( )传递一个s h a p e *型参数,它会认为类型为s h a p e *,所以如 果想知道一个指针所指对象的精确类型,我们必须逆向引用这个指针。比如,s是个s h a p e * , cout << typeid(*s).name()<<endl; 将显示出s所指向的对象类型。 也可以用b e f o r e ( t y p e i n f o & )查询一个t y p e i n f o对象是否在另一个t y p e i n f o对象的前面(以定 义实现的排列顺序),它将返回t r u e或f a l s e。如果写: if(typeid(me).before(typeid(you))) //... 那么表示我们正在查询m e在排列顺序中是否在y o u之前。 RT T I的第二个用法叫“安全类型向下映射”。之所以用“向下映射”这个词也是由于类继 承的排列顺序。如果映射一个c i r c l e *到s h a p e *叫向上映射的话,那么将一个s h a p e *映射成一个 c i r c l e *就叫向下映射了。当然一个c i r c l e *也是一个s h a p e *,编译器允许任意的向上映射,但一 个s h a p e *不一定就是c i r c l e *,所以编译器在没有明确的类型映射时并不允许我们完成一个向下 映射任务。当然可以用原有的C风格的类型映射或C + +的静态映射(s t a t i c c a s t ,将在本章末介绍) 来强制执行,这等于在说:“我希望它实际上是一个c i r c l e *,而且我打算要求它是。”由于并没 有明确地知道它实际上是c i r c l e,因此这样做是很危险的。在开发商制定的RT T I中一般的方法 是:创建一个函数来试着将s h a p e *指派为一个c i r c l e * (在本例中),检查执行过程中的数据类型。 如果这个函数返回一个地址,则成功;如果返回n u l l,说明我们并没有一个c i r c l e *对象。 C + +的RT T I的“安全类型向下映射”就是按照这种“试探映射”函数的格式,但它(非常 合理地)用模板语法来产生这个特殊的动态映射函数( d y n a m i c c a s t),所以本例变成: 动态映射的模板参数是我们想要该函数创建的数据类型,也就是这个函数的返回值。函数 参数是我们试图映射的源数据类型。 通常只要对一种类型作这种工作(比如将三角型变成紫色),但如果想算出各种s h a p e的数 目,可以用面下例子的框架: 当然这是人为的—我们可能已经在各个类型中放了一个静态数据成员并在构造函数中对 第18章运行时类型识别383 下载 shape* sp = new circle; circle* cp = dynamic_cast<circle*>(sp); if(cp) cou七<< "cas 七successful"; circle* cp = dynamic_cas区circle*>(sh); square* sp = dynamic_cast<square*>(sh); triangle* 七p = dynamic_cast<triangle*>(sh); 它自增。如果可以控制类的源代码并可以修改它,当然可以这样做。下面这个例子用来计算 s h a p e的个数,它用了静态数据成员和动态映射两种方法: 384 C + +编程思想 下载 //: RTSHAPES.CPP -- Counting shapes #include <iostream.h> #include< 七ime.h> #include <typeinfo.h> #include"·.\14\tstash.h" class shape { protected: S 七atic in七coun店 public: shape() { count++; vir七ual -shape() = O { count--; } vir七ual void draw () const = O; static in七quan七让y() { return count; }; in七shape : : count = O; class rectangle : public shape void operator=(rectangle&); // Disallow protected: static int count; public: rectangle() { count++; rectangle(const rectangle&) { count++;} -rectangle() { count--; } void draw () cons 七{ cout << "rec 七angle: : draw ()" << endl; S 七atic int quantity() { return count; } ... ' int rectangle: : count = 0; class ellipse : public shape void operator=(ellipse&}; // Disallow protected: static int count; public: ellipse () { count++; } ellipse (const ellipse&) { count++; } ~ellipse() { count 一;} void draw() cons 七{ cout << "ellipse: :draw()" << endl; 第18章运行时类型识别385 下载 } static int quantity() { return count; } }; int ellipse::count = O; class circle: public ellipse { void operator=(circle&); // Disallow protected: static int count; public: circle() { count++; } circle(cons 七circle&) { count++; } 一circle() { count--; } void draw() const { cout << "circle: :draw()" << endl; } static in七quantity() { return count; } } ; int circle::count = 0; main() { 七stash<shape> shapes; time_t t; II Seed random number generator: srand((unsigned)time(&t)); const mod= 12; for(int i = 0; i < rand() 令mod; i++) shapes.add(new rectangle); for(int j = O; j < rand() % mod; j++) shapes.add(new ellipse); for(int k = O; k < rand() 兮mod; k++) shapes.add(new circle); int Ncircles = O; int Nellipses = O; int Nrects = O; int Nshapes = O; for(int u = O; u < shapes.count(); u++) { shapes[u]->draw(); if(dynamic_cast<circle*>(shapes[u])) Ncircles++; if(dynamic_cast<ellipse*>(shapes[u])) Nellipses++; if(dynamic_cast<rectangle*>(shapes[u])) Nrects++; 对于这个例子,两种方法都是可行的,但静态数据成员方法只能用于我们拥有源代码并已 安装了静态数据成员和成员函数时(或者开发商已为我们提供了这些),另外RT T I可能在不同 的类中用法不同。 18.3 语法细节 本节详细介绍RT T I的两种形式是如何运行的以及两者之间的不同。 18.3.1 对于内部类型的typeid() 为了保持一致性, t y p e i d ( )也可以运用于内部类型,所以下面的表达式结果为t r u e: 18.3.2 产生合适的类型名字 t y p e i d ( )必须在所有的状况下都可以运行,比方说,下面的类中包含了一个嵌套类: 386 C + +编程思想 下载 } if(dynamic_cast<shape*>(shapes[u])) Nshapes++; cout << endl << endl <<"circles=• << Ncircles << endl <<"ellipses=• << Nellipses << endl << "rec 七angles="<< Nrects << endl <<"shapes="<< Nshapes << endl << endl << "circle: :quantity() =• << circle: :quantity() << endl << "ellipse: :quantity() = " << ellipse: :quantity() << endl << "rectangle: :quantity() =" << rectangle: : quantity () << endl << "shape: :quantity() =• << shape: :quantity() << endl;
C++中,当需要在运行时将一个指向基类的指针转换为指向派生类的指针时,就会用到RTTI中的dynamic_cast。它的语法如下: Superb *pm = dynamic_cast<Superb *>(pg); 其中,pg是指向基类对象的指针。如果转换成功,dynamic_cast将生成一个指向派生类的指针;如果转换失败,即无法将指向基类的指针转换为指向派生类的指针,dynamic_cast将返回0,即空指针。 此外,dynamic_cast也可以用于引用类型。与指针不同的是,当转换请求不正确时,dynamic_cast将引发一个类型为bad_cast的异常。这种异常是从exception类派生而来的,它是在头文件typeinfo中定义的。因此,在使用dynamic_cast进行引用类型转换时,可以使用try-catch语句来处理可能引发的异常,例如下面的代码片段: try { Superb &rs = dynamic_cast<Superb &>(rg); } catch(bad_cast &) { // 引发类型转换异常的处理代码 } 因此,在C++中,当我们需要在运行时进行指针或引用类型的基类和派生类之间的转换时,可以使用RTTI中的dynamic_cast来实现。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [P39-第15章友元、异常和其他-04RTTI,运行阶段类型识别和dynamic_cast](https://blog.csdn.net/sgy1993/article/details/114402030)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值