Skip to main content
Skip table of contents

Client-Side C++ Mapping for Interfaces

Proxy Classes

On the client side, a Slice interface maps to a C++ proxy class with member functions that correspond to the operations on that interface. Consider the following Slice interface:

SLICE
module M
{
    interface Simple
    {
        void op();
    }
}

The Slice compiler generates the following definitions for use by the client:

CPP
class SimplePrx : public Ice::Proxy<SimplePrx, Ice::ObjectPrx> 
{
public:
    // Constructors
    SimplePrx(
        const Ice::CommunicatorPtr& communicator,
        std::string_view proxyString);
    SimplePrx(const SimplePrx& other) noexcept;
    SimplePrx(SimplePrx&& other) noexcept;
    
    // Assignment operators.
    SimplePrx& operator=(const SimplePrx& rhs) noexcept;
    SimplePrx& operator=(SimplePrx&& rhs) noexcept;

    // Member functions mapped from Slice operation op.

    void op(const Ice::Context& = Ice::noExplicitContext) const;

    [[nodiscard]] std::future<void> opAsync(
        const Ice::Context& context = Ice::noExplicitContext) const;
    
    std::function<void()> opAsync(
        std::function<void()> response, 
        std::function<void(std::exception_ptr)> exception = nullptr, 
        std::function<void(bool)> sent = nullptr, 
        const Ice::Context& context = Ice::noExplicitContext) const;
};

Your client code interacts directly with the proxy classM::SimplePrx in the example above. More generally, the generated proxy class for an interface in module M is the C++ proxy class M::<interface-name>Prx.

In the client's address space, an instance of the proxy class is the local ambassador for a remote instance of an Ice object that implements Simple and is known as a proxy class instance, or simply proxy. All the details about the server-side object, such as its address, what transport to use, and its object identity are encapsulated in that instance.

Notice that all proxy member functions are const – proxy instances are immutable.

The Ice::Proxy template is a mix-in class that adds functionality to the proxy class via inheritance. It derives from the provided base proxy classes (here, only Ice::ObjectPrx):

CODE
template<typename Prx, typename... Bases> 
class Proxy : public virtual Bases...
{
   // Helper functions for Prx
}

It’s an instance of the Curiously Recurring Template Pattern (CRTP).

Creating a Proxy

Use the constructor of the generated class to create a proxy from a communicator and a “stringified” proxy. For example:

CPP
M::SimplePrx simple{communicator, "simple:tcp -h localhost -p 4061"};

A proxy is a stack-allocated C++ object.

The proxy’s constructor does not allow you to create a “null” proxy. A nullable proxy - and by extension a null proxy - is a proxy held in a std::optional. For example:

CPP
// A nullable Simple proxy, default-initialized to std::nullopt.
std::optional<M::SimplePrx> simple;

Inheritance from Ice::ObjectPrx

All generated proxy classes inherit indirectly from the Ice::ObjectPrx class, reflecting the fact that all Slice interfaces implicitly inherit from Object.

Interface Inheritance

Inheritance relationships among Slice interfaces are maintained in the generated C++ classes. For example:

SLICE
module M
{
    interface A { ... }
    interface B { ... }
    interface C extends A, B { ... }
}

The generated code for CPrx reflects the inheritance hierarchy:

CPP
namespace M
{
    class CPrx : public Ice::Proxy<CPrx, APrx, BPrx>
    {
        ...
    };
}

Given a proxy for C, a client can invoke any operation defined for interface C, as well as any operation inherited from C's base interfaces.

Proxy Factory Methods

The base proxy class Ice::ObjectPrx supports a variety of methods for customizing a proxy. Since proxies are immutable, each of these "factory methods" returns a copy of the original proxy that contains the desired modification. For example, you can obtain a proxy configured with a ten second invocation timeout as shown below:

CPP
GreeterPrx greeter{communicator, "greeter:tcp -h localhost -p 4061"};

// Create a new GreeterPrx and assign it to greeter.
greeter = greeter.ice_invocationTimeout(10000); 

The factory methods usually return a proxy of the same type as the current proxy, as in the example above.

The only exceptions are the factory methods ice_facet and ice_identity. Calls to either of these functions may produce a proxy for an object of an unrelated type, and you need to supply the desired proxy type when you call them. For example:

CPP
GreeterPrx greeter{communicator, "greeter:tcp -h localhost -p 4061"};
GreeterAdminPrx greeterAdmin = greeter.ice_facet<GreeterAdminPrx>("admin");
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.