There are four possibilities I see here:
Possibility 1 - NBD
It's not a big deal so long as exposing
Component::Client does not leak much of the implementation details. If you feel like this is the type of interface you want to expose and you are not expecting to have any dramatic changes that would invalidate this interface, then it might just be No Big Deal™.
Possibility 2 -
Component::Clients are mostly data
If the external interface of a
Component::Client is mostly data, then instead of asking for one directly, just ask for the data parts you need to make one, and just make it internally instead. If there is only one or a few fixed internal implementations of
Component::Client, you might be in this situation. So if your calling code looks like:
Component::Client client(data, filters, listeners, etc);
// client is never used again
Then as far as the calling code is concerned, the client is just a data store being passed to the component. Even though the client may have a load of behavior on it, if it is only interesting to the component, then externally it is irrelevant, and you could change the method to be:
component.AddClient(11, data, filters, listeners, etc);
// What client?
AddClient method would internally create and store the
Component::Client instance, but external code would never know about it. (If creating a
Component::Client instance is particularly complicated, there are ways to bend patterns like a builder to what you might need.)
Possibility 3 -
Component::Clients are mostly behavior
If you are passing in a
Component::Client instance to an
IComponent instance mostly to provide behavior, then exposing the
Component::Client might not be avoidable. Using it as a strategy object is a form of providing behavior, for instance. There are two ways that behavior might be being provided.
Possibility 3, Part 1 - Client code creates a
Component::Client from a fixed number of provided implementations
If there are a few implementations of
Component::Client that your client code must choose from and then pass in, you could instead have that client code pass in an enum (or similar). The enum would tell the
AddClient method which type of
Component::Client implementation to create and store internally. Note that though the class is not exposed, an enum is exposed instead.
Possibility 3, Part 2 - Client code extends
Component::Client to provide custom implementations
There's not a whole lot here you can do but to expose
Component::Client. Client code needs to see it to extend it. If you only need a little bit of additional behavior for an otherwise very large internal implementation, you could expose a much simpler strategy interface for clients to implement and hide the bulk of the
Component::Client. You might even be able to repurpose a pre-existing interface (in the standard library or elsewhere in your own) to meet your needs.
Possibility 4 - Possibility 2 + Possibility 3
If you have a
Component::Client that is providing both behavior and data, then you can look at it two ways. First, it could just make sense then, and you should leave it alone (aka, Possibility 1). Or, you could break apart the behavior and the data, then do Possibility 2 and Possibility 3 with the newly split parts. Keep in mind single responsibility as you do this: A class should have a single responsibility, not more and not less.
As a final note, I want to point out that in all cases, the idea of a component client still exists to the client code. Often, having a class or type to represent that is beneficial, even if only a data value or behavioral value object.