1

Right now I'm working on a project where convertibility between two classes (A and B) is highly desirable. I've created a function myFunc() that takes an object of class A as its argument, and I've passed it an object of class B.

The reason I expected this to work is that B can be implicitly converted to an integer, and A can be implicitly constructed with an integer. I expected these two processes to occur so that an object of class B would implicitly be converted to an object of class A. This was not the case.

When I try to pass in an object of class B to myFunc(), I get the error: error: could not convert 'b' from 'B' to 'A'.

Interestingly, however, I can pass in an object of class B that I explicitly cast to an integer, or an explicitly constructed object of class A which takes an object of class B as its argument. It seems that only one implicit process (whether it be a converting constructor or an implicit conversion) can happen in a single line. Why is this the case? Is there any way to get around this issue?

I know that a simple solution would be to create a constructor in A that takes an object of class B as its argument, or to create an operator in B that converts an object of class B to an object of class A. For my purposes, however, these solutions should not be used unless absolutely necessary.

I'm still learning C++ (I've come over from Java). Hopefully the code below will clarify what I'm talking about. Thank you for your feedback in advance.

#include <iostream>

// objects of class A can be (implicitly) constructed with an int
struct A {
    A(int) {}
};

// objects of class B can be (implicitly) converted to an int
struct B {
    B(int) {}
    operator int() { return 0; }
};

// myFunc takes an object of class A
void myFunc(A)
{ }

// why can't myFunc convert the argument b like the following: B -> int -> A?
int main()
{
    B b(5);

    // These work:
    myFunc((int) b);
    myFunc(A(b));

    // This does not:
    myFunc(b);
}

Note: The code above should compile properly until myFunc(b); is commented out.

Nikos C.
  • 50,738
  • 9
  • 71
  • 96
ggrajeda
  • 13
  • 3
  • Unrelated to your problem, and an easy mistake to make since you're new, but please don't use what's called C-style casting (or perhaps Java-style casting, considering where you come from) like `(int) b`. It's often seen as a "red flag" that there's something bad going on, perhaps silencing a compiler warning (about behavior that could lead to *undefined behavior*) or even error messages that shouldn't be silenced. In this case you should use [`static_cast`](https://en.cppreference.com/w/cpp/language/static_cast). – Some programmer dude Jun 06 '19 at 22:38
  • @Someprogrammerdude In many context a C style cast is OK: when the construct can only be a `static_cast`. – curiousguy Jun 07 '19 at 00:38

1 Answers1

1

What you're looking for is called a conversion sequence in C++. To get from one type to another, there can be only a limited number of steps. Importantly, there can be at most one step from each of the possible categories. E.g. you can have at most one numeric promotion ( e.g. short to long.). Importantly for your example, there can be at most one user-defined conversion. This is either a converting constructor (Foo::Foo(Bar)) or a conversion function (Bar::operator Foo). Your example needs both.

MSalters
  • 173,980
  • 10
  • 155
  • 350