Bonjour,
Voilà maintenant 3 jours que je parcours le net à la recherche d’une réponse (Francophone et anglophone), même la doc du langage.
Voici le code que je suis en train de tester et ma question qui le succède:
#include <string>
#include <unordered_map>
#include <memory>
class BaseNode
{
private:
std::string m_identifier;
protected:
virtual void deleteNode() = 0;
public:
BaseNode(){}
BaseNode(std::string const& p_identifier) : m_identifier(p_identifier){}
BaseNode(BaseNode const& rhs){ m_identifier = rhs.getIdentifier(); }
virtual ~BaseNode(){}
std::string const& getIdentifier() const { return m_identifier; }
void setIdentifier(std::string const& p_identifier) { m_identifier = p_identifier; }
};
class NodeHandler : public BaseNode
{
protected:
std::unordered_map<std::string, std::unique_ptr<BaseNode>> m_handler;
virtual void deleteNode() = 0;
virtual void clear() = 0;
public:
NodeHandler(std::string const& p_identifier) : BaseNode(p_identifier) {
m_handler.clear();
}
virtual ~NodeHandler(){}
virtual void loadNewNode(BaseNode const& p_newNode) = 0;
virtual BaseNode* getNode(std::string const& p_identifier) = 0;
};
class AssetNode : public BaseNode
{
private:
std::string m_filePath;
protected:
virtual void deleteNode() = 0;
public:
AssetNode(){}
AssetNode(std::string const& p_identifier, std::string const& p_filePath) : BaseNode(p_identifier), m_filePath(p_filePath) {}
AssetNode(AssetNode const& rhs) : BaseNode(rhs.getIdentifier()), m_filePath(rhs.getFilePath()) {}
virtual ~AssetNode(){}
std::string const& getFilePath() const { return m_filePath; }
void setFilePath(std::string const& p_filePath) { m_filePath = p_filePath; }
};
class TextureNode : public AssetNode
{
private:
virtual void deleteNode() override {}
public:
TextureNode(){}
TextureNode(std::string const& p_identifier, std::string const& p_filePath) : AssetNode(p_identifier, p_filePath) {}
TextureNode(TextureNode const& rhs) : AssetNode(rhs.getIdentifier(), rhs.getFilePath()) {}
~TextureNode() { deleteNode(); }
};
class TextureHandler : public NodeHandler
{
private:
virtual void deleteNode() override {}
virtual void clear() override { m_handler.clear(); }
public:
TextureHandler(std::string const& p_identifier) : NodeHandler(p_identifier) { clear(); }
~TextureHandler() { clear(); }
virtual void loadNewNode(BaseNode const& p_newNode) override {
m_handler.insert({p_newNode.getIdentifier(), std::make_unique<TextureNode>(p_newNode)});
}
virtual BaseNode* getNode(std::string const& p_identifier) override {
return (TextureNode*)m_handler[p_identifier].get();
}
};
int main() {
TextureHandler t_handler("Texture Handler");
t_handler.loadNewNode(TextureNode("Texture", "texture.png"));
return 0;
}
En compilant avec g++ testnode.cpp -std=c++17 -Wall -Wextra -pedantic -O2 -o testnode.out
j’obtiens la baffe dans la tronche suivante:
In file included from /usr/include/c++/8/memory:80,
from testnode.cpp:3:
/usr/include/c++/8/bits/unique_ptr.h: In instantiation of ‘typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = TextureNode; _Args = {const BaseNode&}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<TextureNode, std::default_delete<TextureNode> >]’:
testnode.cpp:86:97: required from here
/usr/include/c++/8/bits/unique_ptr.h:831:30: error: no matching function for call to ‘TextureNode::TextureNode(const BaseNode&)’
{ return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
testnode.cpp:70:9: note: candidate: ‘TextureNode::TextureNode(const TextureNode&)’
TextureNode(TextureNode const& rhs) : AssetNode(rhs.getIdentifier(), rhs.getFilePath()) {}
^~~~~~~~~~~
testnode.cpp:70:9: note: no known conversion for argument 1 from ‘const BaseNode’ to ‘const TextureNode&’
testnode.cpp:69:9: note: candidate: ‘TextureNode::TextureNode(const string&, const string&)’
TextureNode(std::string const& p_identifier, std::string const& p_filePath) : AssetNode(p_identifier, p_filePath) {}
^~~~~~~~~~~
testnode.cpp:69:9: note: candidate expects 2 arguments, 1 provided
testnode.cpp:68:9: note: candidate: ‘TextureNode::TextureNode()’
TextureNode(){}
^~~~~~~~~~~
testnode.cpp:68:9: note: candidate expects 0 arguments, 1 provided
Voici donc ma question: Comment puis-je procéder afin qu’en passant n’importe quel objet dérivé de BaseNode
à la fonction TextureHandler::loadNewNode(BaseNode const& p_newNode)
il utilise le constructeur de copie de l’objet dérivé et non celui de la classe abstraite BaseNode
(Ligne 86) ? Je pense que j’ai dû louper une marche quelque part.
Je ne souhaite pas utiliser un pansement Template, sinon la hiérarchie de ces objets n’aurait aucun sens.
Désolé pour le pavé(César)
Merci d’avance.
EDIT: Le seul moyen que j’ai trouvé pour régler le problème est de déclarer dans chaque handler dérivé de NodeHandler
une fonction loadNewNode()
et getNode()
avec directement le type dérivé en paramètres.
Dans ce cas là, la classe NodeHandler
ne fait qu’encapsuler la déclaration du std::unique_ptr
et l’appel à la fonction clear()
du std::unordered_map<>
dans son constructeur. Cela casse un peu le rythme de la POO non ?