将派生对象分配给函数内的基类指针
Posted
技术标签:
【中文标题】将派生对象分配给函数内的基类指针【英文标题】:Assigning a a derived object to a baseclass pointer inside a function 【发布时间】:2018-07-02 15:31:50 【问题描述】:我有一个基类,
struct MsgFormat
MsgFormat();
virtual ~MsgFormat();
const std::string rootNode;
;
还有一个派生类,
class ServiceMsg : public MsgFormat
public:
explicit ServiceMsg(std::string A, std::string B);
ServiceMsg();
ServiceMsg(const ServiceMsg& srvMsg);
class ServiceMsg& operator=(const ServiceMsg& srvMsg);
~ServiceMsg();
std::string A() const;
std::string B() const;
private:
std::string m_A;
std::string m_B;
;
现在我有一个消息处理程序类,它接受一个指向基类的指针,就像这样,
class MsgHandler
public:
MsgHandler();
virtual ~MsgHandler();
virtual int parseIncoming(struct MsgFormat* pBaseMsg) = 0;
virtual int formatOutgoing(const struct HermesMsgFormat* const pBaseMsg) = 0;
;
;
现在,如果我在 main() 中做这样的事情,
ServiceMsg* pSrvMsg = new ServiceMsg("foo", "bar");
SpecificMsgHandler m_handle->formatOutgoing(pSrvMsg);
在重载的 formatOutgoing 方法中,我有这样的东西,
virtual int CustomMsgHandler::formatOutgoing(const struct MsgFormat* const pBaseMsg)
const ServiceMsg* const pServiceMsg = dynamic_cast<const ServiceMsg* const>(pBaseMsg);
std::cout << pServiceMsg->A() << std::endl;
std::cout << pServiceMsg->B() << std::endl;
CustomMsgHandler 继承自 MsgHandler 类,一切都很好。这就是我猜多态性的整个想法。您可以将派生类的对象传递给接受指向基类的指针的接口。
不起作用的是,相反。其中 parseIncoming() 执行以下操作,
virtual int CustomMsgHandler::parseIncoming(struct MsgFormat* pBaseMsg)
pBaseMsg = new ServiceMsg("bla", "baa");
#ifdef NDEBUG
ServiceMsg* pServiceMsg = dynamic_cast<ServiceMsg*>(pBaseMsg);
std::cout << pServiceMsg->A() << std::endl;
std::cout << pServiceMsg->B() << std::endl;
std::cout << "all good here" << std::endl;
#endif
我在 main() 中执行以下操作。
MsgFormat* pBaseMsg = new pBaseMsg();
SpecificMsgHandler m_handle->parseIncoming(pBaseMsg);
但是如果我尝试从 main() 中的 pBaseMsg 读取,在从调用返回 parseIncoming 消息后,我没有得到“bla”和“baa”。我得到了默认构造函数中设置的内容。
ServiceMsg* pServiceMsg = dynamic_cast<ServiceMsg*>(pBaseMsg);
std::cout << pServiceMsg->A() << std::endl;
std::cout << pServiceMsg->B() << std::endl;
std::cout << "all good here" << std::endl;
我不明白为什么第二种情况不起作用。或者如何最好地让它发挥作用?
【问题讨论】:
分配给一个(非引用)参数在函数之外没有任何影响。parseIncoming()
方法的目的是创建消息吗?从他们的名字来看,您的方法似乎应该做相反的事情。请说明您应该使用哪种方法(如果有)来创建消息。
@molbdnilo,我正在传递一个指针。我正在为函数内的该指针分配一个新对象。这与通过引用传递变量“实际上”有何不同?
@r3musn0x,函数名称无关紧要,仅反映我正在尝试编写的模块。 parseIncoming() 和 formatOutgoing() 之间唯一真正的区别是,它接受已经在方法之外创建的派生类的对象。另一方面,第二个函数在方法内创建派生类的对象,并尝试将其分配给基类指针 - 即作为函数参数的基类指针。我期待一旦这个函数返回,基类指针就会在方法中分配给它的对象。
指针没有什么特别之处。如果要修改变量,则需要将指针(或引用)传递给该变量,无论该变量是否为指针。
【参考方案1】:
您正在按值传递指针。该函数将复制您传入的指针,然后您修改该副本。这就是函数调用后在main
中看不到更改的原因。
要解决此问题,您可以改为通过引用传递指针,方法是更改函数的签名。
virtual int CustomMsgHandler::parseIncoming(struct MsgFormat*& pBaseMsg) //added &, it's now a reference to a pointer.
另请注意,您首先在main
中进行动态分配。
MsgFormat* pBaseMsg = new pBaseMsg();
然后你将这个指针传递给函数并再次进行动态分配。
pBaseMsg = new ServiceMsg("bla", "baa");
在这里你忘记了delete
指针,所以你泄漏了内存。每次调用new
都需要调用delete
以释放内存。 (除非它被传递给类似智能指针的构造函数,否则智能指针会为你处理delete
ing。)
使用 c++11 或 boost 等效项时
在现代 C++ 中确实没有必要使用裸 new
和 delete
。您应该改用 std::vector
、std::unique_ptr
和 std::shared_ptr
之类的东西。
【讨论】:
感谢您的回答。我将尝试您提到的“通过引用传递指针”解决方案,并将回复您。我有一种感觉,我必须这样做或使用指针。 关于内存泄漏,我稍后会在代码中删除指针。这只是真实事物的切碎和缩减版本,仅显示我有问题/怀疑的部分。但无论如何,谢谢你提到它。关于智能指针和现代 C++,谁说我使用的是现代 C++? :P 我绑定到项目中使用的编译器。这不是我的选择。手头没有 std::unique_ptr 和 std::shared_ptr 。如果你会说,那就使用 Boost,那么答案是,我不做那个决定。工具和库是固定的。我既没有 C++11/newer 也没有 Boost。 @JoeyMallone 只是为了在上面的评论中澄清您的问题,传递指针和对变量的引用实际上有何不同。当您传递一个指针时,指针指向的对象可以被修改,并且该更改将反映在函数之外。在您的示例中,您并没有这样做。您正在修改指针本身,而不是指针指向的对象。 @JoeyMallone 我明白了。在这种情况下,这确实是这样做的方法,除非您想编写自己的智能指针包装器。在未来读者的答案中指出这一点仍然很好。我将通过在该选项所需的c++11
上方添加注释来澄清。
Alles klar!委员长! ;) 谢谢!以上是关于将派生对象分配给函数内的基类指针的主要内容,如果未能解决你的问题,请参考以下文章