Herança no C++ Interop

Quando comecei a converter as classes da aplicação V-ART para C# me deparei com um problema relacionado a classes que se relacionavam por herança no C++ Interop. Após tentar algumas alternativas sem sucesso e também enfrentar alguns problemas obscuros de alocação de memória relacionados a string marshaling consegui uma solução temporária. Está longe de ser a ideal, mas funciona enquanto não encontro uma alternativa.

Herança

Logo no início da aplicação aparece a classe Transform que, por sua vez, é filha da classe SceneNode que é filha da classe MemoryObj. Como a classe MemoryObj apenas trata de detalhes de gerência de memória somente pertinentes ao C++, comecei a escrever o wrapper a partir da SceneNode. Minha primeira e ingênua tentativa foi criar um wrapper conforme o esqueleto abaixo (o mesmo usado anteriormente para a classe Point4D) para a SceneNode e outro igual para o Transform e então fazer a classe managed Transform herdar da classe managed SceneNode.

public ref class ManagedClass {
public:
   // Construtor: aloca um objeto da classe Unmanaged
   ManagedClass() : m_Impl( new UnmanagedClass ) {}
   
   // Destrutores omitidos
private:
   UnmanagedClass * m_Impl; // Ponteiro para instância da classe Unmanaged
};


O problema com essa alternativa é que ao instanciar um elemento da classe Transform estamos, na verdade, criando duas instâncias unmanaged totalmente independentes: uma da classe SceneNode e outra da classe Transform.

A solução adotada não é lá muito elegante nem robusta. É mais um workaround temporário até que uma solução melhor seja encontrada (se existir).

namespace VartCLR
{
        // Classe SceneNode
	public ref class SceneNode
	{
	public:
		// Allocate the native object on the C++ Heap via a constructor
		SceneNode() {};
		//Deallocate the native object on a destructor
		~SceneNode() {
			delete m_BaseImpl;
		}

	protected:
		//Deallocate the native object on the finalizer just in case no destructor is called
		!SceneNode() {
			delete m_BaseImpl;
		}

		VART::SceneNode *m_BaseImpl;
	};

        // Classe Transform
	public ref class Transform : SceneNode
	{
	public:
		// O Construtor aloca um objeto da classe transform no ponteiro m_BaseImpl do tipo VART::SceneNode*, usado pela classe
                // mãe. Depois uma referência ao mesmo objeto é guardada como VART::Transform* na variável m_Impl usada pela
                // classe Transform.
		Transform() {
			m_BaseImpl = new VART::Transform;
			m_Impl = (VART::Transform*) m_BaseImpl;
		}

	protected:
		void MakeTranslation(Point4D^ translationVector){
			VART::Point4D p(translationVector->X, translationVector->Y, translationVector->Z, translationVector->W);
			m_Impl->MakeTranslation(p);
		}

		void MakeTranslation(double tx, double ty, double tz){
			m_Impl->MakeTranslation(VART::Point4D(tx,ty,tz,0));
		}

	private:
		VART::Transform *m_Impl;
	};
}


Note que caso seja necessário criar uma classe que herde de Transform, essa implementação já vai precisar ser alterada para que apenas um objeto seja alocado e repassado para cima na árvore de herança.

Last edited Aug 1, 2008 at 7:56 PM by kcfelix, version 1

Comments

No comments yet.