C ++ / CLI - C++/CLI

C ++ / CLI
Paradigma Estruturado , imperativo , orientado a objetos
Família C
Projetado por Microsoft
Desenvolvedor Microsoft
Apareceu pela primeira vez 2005 ; 16 anos atrás  ( 2005 )
Versão estável
Norma ECMA-372 / Dezembro 2005 ; 15 anos atrás  ( 2005-12 )
Plataforma Infraestrutura de linguagem comum
Local na rede Internet www .ecma-international .org / publicações / padrões / Ecma-372 .htm
Influenciado por
C ++ , extensões gerenciadas para C ++ , C #

C ++ / CLI (C ++ modificado para Common Language Infrastructure ) é uma especificação de linguagem criada pela Microsoft que substitui Managed Extensions para C ++ . É uma revisão completa que simplifica a sintaxe C ++ gerenciada agora obsoleta e fornece interoperabilidade com linguagens Microsoft .NET, como C # . C ++ / CLI foi padronizado pela Ecma como ECMA-372 . Atualmente, está disponível no Visual Studio 2005, 2008, 2010, 2012, 2013, 2015, 2017 e 2019, incluindo as edições Express.

Mudanças de sintaxe

C ++ / CLI deve ser pensado como uma linguagem própria (com um novo conjunto de palavras-chave, por exemplo), em vez do C ++ gerenciado orientado a superconjunto C ++ (MC ++) (cujas palavras-chave não padrão eram estilizadas como __gc ou __value ). Por causa disso, há algumas mudanças sintáticas importantes, especialmente relacionadas à eliminação de identificadores ambíguos e à adição de recursos específicos do .NET.

Muitas sintaxes conflitantes, como as várias versões do operador em MC ++, foram divididas: em C ++ / CLI, os tipos de referência .NET são criados com a nova palavra-chave (isto é, coleta de lixo new ()). Além disso, C ++ / CLI introduziu o conceito de genéricos do .NET (semelhante, para os fins mais comuns, aos modelos C ++ padrão, mas bastante diferente em sua implementação). new()gcnew

Alças

Em MC ++, havia dois tipos diferentes de ponteiros : __nogc ponteiros eram ponteiros normais de C ++, enquanto __gc ponteiros funcionavam em tipos de referência .NET. Em C ++ / CLI, entretanto, o único tipo de ponteiro é o ponteiro normal de C ++, enquanto os tipos de referência .NET são acessados ​​por meio de um "identificador", com a nova sintaxe (em vez de ). Essa nova construção é especialmente útil quando gerenciado e o código C ++ padrão é misturado; ele esclarece quais objetos estão sob a coleta de lixo automática .NET e quais objetos o programador deve se lembrar de destruir explicitamente. ClassName^ClassName*

Referências de rastreamento

Uma referência de rastreamento em C ++ / CLI é um identificador de uma variável passada por referência. É semelhante em conceito ao uso de " *& " (referência a um ponteiro) em C ++ padrão e (em declarações de função) corresponde à ref palavra-chave " " aplicada a tipos em C # ou " ByRef " em Visual Basic .NET . C ++ / CLI usa uma ^% sintaxe " " para indicar uma referência de rastreamento a um identificador.

O código a seguir mostra um exemplo do uso de referências de rastreamento. Substituir a referência de rastreamento por uma variável de identificador regular deixaria o array de string resultante com 10 identificadores de string não inicializados, já que apenas cópias dos identificadores de string no array seriam definidas, devido ao fato de serem passados ​​por valor em vez de por referência.

int main()
{
    array<String^> ^arr = gcnew array<String^>(10);
    int i = 0;

    for each(String^% s in arr) {
        s = i++.ToString();
    }

    return 0;
}

Observe que isso seria ilegal em C #, que não permite que os foreach loops passem valores por referência. Portanto, uma solução alternativa seria necessária.

Finalizadores e variáveis ​​automáticas

Outra mudança em C ++ / CLI é a introdução da sintaxe do finalizador , um tipo especial de destruidor não determinístico que é executado como parte da rotina de coleta de lixo . A sintaxe do destruidor C ++ também existe para objetos gerenciados e reflete melhor a semântica C ++ "tradicional" de destruição determinística (isto é, destruidores que podem ser chamados pelo código do usuário com ). !ClassName()~ClassName()delete

No paradigma .NET bruto, o modelo de destruição não determinística substitui o Finalize método protegido da Object classe raiz , enquanto o modelo determinístico é implementado por meio do método de IDisposable interface Dispose (no qual o compilador C ++ / CLI transforma o destruidor). Objetos de código C # ou VB.NET que substituem o método Dispose podem ser descartados manualmente em C ++ / CLI delete da mesma forma que as classes .NET em C ++ / CLI podem.

// C++/CLI
ref class MyClass
{
public:
    MyClass();  // constructor
    ~MyClass(); // (deterministic) destructor (implemented as IDisposable.Dispose())
protected:
    !MyClass(); // finalizer (non-deterministic destructor) (implemented as Finalize())

public:
    static void Test()
    {
        MyClass automatic; // Not a handle, no initialization: compiler calls constructor here
 
        MyClass ^user = gcnew MyClass();
        delete user;

        // Compiler calls automatic's destructor when automatic goes out of scope
    }
};

Sobrecarga do operador

A sobrecarga do operador funciona de forma análoga ao C ++ padrão. Todo * se torna um ^, todo & se torna um%, mas o resto da sintaxe permanece inalterado, exceto por uma importante adição: para classes .NET, a sobrecarga de operador é possível não apenas para as próprias classes, mas também para referências a essas classes. Esse recurso é necessário para fornecer a uma classe ref a semântica para a sobrecarga de operador esperada das classes ref .NET. (Em reverso, isso também significa que para classes ref do .NET framework, a sobrecarga do operador de referência geralmente é implementada implicitamente em C ++ / CLI.)

Por exemplo, comparar duas referências de String distintas (String ^) por meio do operador == resultará em true sempre que as duas strings forem iguais. A sobrecarga do operador é estática, no entanto. Portanto, a conversão para Object ^ removerá a semântica de sobrecarga.

//effects of reference operator overloading
String ^s1 = "abc";
String ^s2 = "ab" + "c";
Object ^o1 = s1;
Object ^o2 = s2;
s1 == s2; // true
o1 == o2; // false

Interoperabilidade C ++ / C #

C ++ / CLI permite que programas C ++ consumam programas C # em DLLs C #. Aqui, a palavra-chave #using mostra ao compilador onde a DLL está localizada para seus metadados de compilação. Este exemplo simples não requer organização de dados .

#include "stdafx.h"
using namespace System;
#using "...MyCS.dll"

int main(array<System::String ^> ^args) {
    double x = MyCS::Class1::add(40.1, 1.9);
    return 0;
}

O conteúdo do código-fonte C # de MyCS.DLL.

namespace MyCS {
    public class Class1 {
        public static double add(double a, double b) {
            return a + b;
        }
    }
}

Este exemplo mostra como as strings são organizadas de strings C ++ para strings chamáveis ​​de C # e de volta para strings C ++. O marshalling de string copia o conteúdo da string para formulários utilizáveis ​​em diferentes ambientes.

#include <string>
#include <iostream>
#include <msclr\marshal_cppstd.h>
#include "stdafx.h"
using namespace System;
#using "..MyCS.dll"

int main() {
	std::string s = "I am cat";
	System::String^ clrString = msclr::interop::marshal_as<System::String^>(s); // string usable from C#
	System::String^ t = MyCS::Class1::process(clrString); // call C# function
	std::string cppString = msclr::interop::marshal_as<std::string>(t); // string usable from C++
	std::cout << "Hello, C++/C# Interop!" << std::endl;
	std::cout << cppString << std::endl;
	return 0;
}

O código C # não reconhece C ++ de forma alguma.

namespace MyCS {
    public class Class1 {
        public static string process(string a) {
            return a.Replace("cat", "dog") + " with a tail";
        }
    }
}

A interoperabilidade C ++ / C # permite C ++ acesso simplificado a todo o mundo de recursos .NET.

C ++ / CX

C ++ / CX direcionado ao WinRT , embora produza código totalmente não gerenciado, empresta a sintaxe ref e ^ para os componentes de contagem de referência do WinRT, que são semelhantes aos "objetos" COM .

Referências

links externos