std::dynamic_pointer_cast 成功调用非初始化 class

std::dynamic_pointer_cast successful call on non initialized class

我写了一个最小的例子来测试一些行为。我试图让 std::dynamic_pointer_cast 失败,但遇到了意外行为。

这是我使用的最小示例:

//virtual_ipsum.h
class virtual_ipsum
{
public:
    virtual_ipsum() { }
    virtual ~virtual_ipsum() { }
};
//derived_lorem.h
#include "virtual_ipsum.h"
#include <iostream>
#define UUID_DERIVED_LOREM_RANDOM 2 //rolled it myself
class derived_lorem :
    public virtual_ipsum
{
public:
    derived_lorem(){ }
    ~derived_lorem(){ }
    void o(){ std::cout << "lorem" << std::endl; };
};
//derived_adipiscing.h
#include "virtual_ipsum.h"
#include <iostream>
#define UUID_DERIVED_ADIPISCING_RANDOM 24 //rolled it myself
class derived_adipiscing :
    public virtual_ipsum
{
public:
    derived_adipiscing(){ }
    ~derived_adipiscing(){ }
    void elit(){ std::cout << "donec" << std::endl; };
};
//server.h
#include <memory>
#include "virtual_ipsum.h"
//note that the header of the server can not contain the derived classes.

class server
{
public:
    server() {}
    ~server() {}
    std::shared_ptr<virtual_ipsum> getDerivedClassByUUID(int UUID);
};
//server.cpp
#include "server.h"
#include "derived_lorem.h"
std::shared_ptr<virtual_ipsum> server::getDerivedClassByUUID(int UUID)
{
    // after careful examination of the UUID the
    // server will send the correct derived class
    return std::make_shared<derived_lorem>();
}
//client.h
#include <memory>
#include "server.h"
class client
{
private:
    std::shared_ptr<server> s;
public:
    client(std::shared_ptr<server> s) : s(s){}
    ~client(){}
    void dolor();
    void consectetur();
};
//client.cpp
#include "client.h"
#include "derived_lorem.h"
#include "derived_adipiscing.h"
#include <memory>
void client::dolor()
{
    std::shared_ptr<virtual_ipsum> sit = s->getDerivedClassByUUID(UUID_DERIVED_LOREM_RANDOM);
    std::shared_ptr<derived_lorem> amet = std::dynamic_pointer_cast<derived_lorem>(sit);
    amet->o();
}
void client::consectetur()
{
    std::shared_ptr<virtual_ipsum> felis = s->getDerivedClassByUUID(UUID_DERIVED_LOREM_RANDOM);
    //everything should crash and burn
    std::shared_ptr<derived_adipiscing> mauris = std::dynamic_pointer_cast<derived_adipiscing>(felis);
    mauris->elit();
}
//main.cpp
#include <memory>
#include "server.h"
#include "client.h"

void main()
{
    std::shared_ptr<server> s = std::make_shared<server>();
    std::shared_ptr<client> c = std::make_shared<client>(s);
    c->dolor();
    c->consectetur();
}

我机器上的输出是:

c->consectetur(); 的调用应该会失败,因为服务器返回了错误的派生 class。取而代之的是,演员表不仅成功而且完成了,如果它是正确的 class.

如何在投射期间在客户端检测到该问题?

正如以上评论所指出的:

  • 调用 mauris->elit(); 未定义。
  • std::shared_ptr 可以简单地进行空检查。
  • void main让人不爽

将客户端的实现更改为以下内容可解决问题。

#include "client.h"
#include "derived_lorem.h"
#include "derived_adipiscing.h"
#include <memory>

void client::dolor()

{
    std::shared_ptr<virtual_ipsum> sit = s->getDerivedClassByUUID(UUID_DERIVED_LOREM_RANDOM);
    std::shared_ptr<derived_lorem> amet = std::dynamic_pointer_cast<derived_lorem>(sit);
    if (amet)
    {
        amet->o();
    }
    else
    {
        std::cout << "amet is null" << std::endl;
    }

}

void client::consectetur()
{
    std::shared_ptr<virtual_ipsum> felis = s->getDerivedClassByUUID(UUID_DERIVED_LOREM_RANDOM);
    //everything should crash and burn
    std::shared_ptr<derived_adipiscing> mauris = std::dynamic_pointer_cast<derived_adipiscing>(felis);

    if (mauris)
    {
        mauris->elit();
    }
    else
    {
        std::cout << "mauris is null" << std::endl;
    }
}

新输出: