0

I have a Interface named IDBAbstractFactory and two derived class CPostgreSQLDBAbstractFactory and COracleDBAbstractFactory.
I am trying to create a

std::unique_ptr<IDBAbstractFactory>

with below code which is not working

std::unique_ptr<IDBAbstractFactory> up((dbType == DATABASE_NAME::POSTGRES) ? new CPostgreSQLDBAbstractFactory : new COracleDBAbstractFactory);

The error I'm getting is

Error (active)  E0042   operand types are incompatible ("CPostgreSQLDBAbstractFactory *" and "COracleDBAbstractFactory *")  
Error   C2446   ':': no conversion from 'COracleDBAbstractFactory *' to 'CPostgreSQLDBAbstractFactory *'

However below code works fine.

IDBAbstractFactory* pIDBAbstractFactory;
if(dbType == DATABASE_NAME::POSTGRES)
        pIDBAbstractFactory = new CPostgreSQLDBAbstractFactory();
else
        pIDBAbstractFactory = new COracleDBAbstractFactory();

 std::unique_ptr<IDBAbstractFactory> up(pIDBAbstractFactory); 

How can I create the unique_ptr with single line code. I am looking for creating the static unique_ptr.

273K
  • 29,503
  • 10
  • 41
  • 64
  • 3
    The two halves of a ternary operator are required to have the same type (this is a gross simplification). If you want to use a ternary operator then you are going to have to add explicit upcasts `unique_ptr up = condition ? static_cast(new Derived1) : static_cast(new Derived2);` – john Apr 25 '23 at 15:23

3 Answers3

3

Use a factory function:

std::unique_ptr<IDBAbstractFactory> make_factory(DATABASE_NAME dbType)
{
    if(dbType == DATABASE_NAME::POSTGRES)
        return std::make_unique<CPostgreSQLDBAbstractFactory>();
    else
        return std::make_unique<COracleDBAbstractFactory>();
}

Then you can use it like

std::unique_ptr<IDBAbstractFactory> up = make_factory(dbType);
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
1

The ternary operator requires operands to be of equal types. Use an initializing closure

std::unique_ptr<IDBAbstractFactory> up = [](auto dbType) -> std::unique_ptr<IDBAbstractFactory> {
    if(dbType == DATABASE_NAME::POSTGRES)
        return std::make_unique<CPostgreSQLDBAbstractFactory>();
    else
        return std::make_unique<COracleDBAbstractFactory>();
}(dbType);

Or cast operands types to CPostgreSQLDBAbstractFactory* as it's mentioned in the comment.

273K
  • 29,503
  • 10
  • 41
  • 64
1
int in1;
int in2;
std::cin >> in1 >> in2;
root* pt = in1 == in2 ? new high1 : new high2; //operand types are incompatible
root* pt = in1 == in2 ? dynamic_cast<root*>(new high1) : dynamic_cast<root*>(new high2); // Works

I think you should have a good understanding of how inheritance and polymorphism works in C++, the way you create a unique pointer to base class and then put the created child object in that pointer something calls object slicing happens, and you'll lose all the information of child's class, what you should be doing if you're looking for polymorphism ("Controlling child objects through common parent") is you first have to create the child object then you have to create a pointer to the base class and assign the pointer to the child object something that I have done in my code. that's why compiler says the operand are incompatible because you cant assign two different types to one type, type 'high1' and 'high2' are different from each other.

My advise is to have a vector of each type object and create that type of object when needed then you can maintain a vector of pointer to base class and each time you create a child, put its address in the vector of pointer to base class as well, then control your objects through that vector, or otherwise you'll lose childs functionality, or you'll need to upcast with dynamic_cast for each call on childs methods which you should be careful and upcast a object which its original type has that functionality, but if you dont maintain child objects chances are you won't know. Also note that std::unique_ptr::make_unique does not create a pointer its creates an object of specified type in the heap and of course that object has an address and other functionalities for making the ownership unique.

Suggested Further reading:

https://www.learncpp.com/cpp-tutorial/virtual-functions/

https://www.learncpp.com/cpp-tutorial/object-slicing/

https://www.learncpp.com/cpp-tutorial/dynamic-casting/

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/

Shahrooz
  • 196
  • 1
  • 14
  • Why do you use a completely different names pt, in1, in2, high1, high2, root instead of just fixing OP's code? Is it a ChatGPT answer? BTW `dynamic_cast` is overkill here. And the vector advise is completely out of topic. – 273K Apr 25 '23 at 17:56
  • code snippet completed, thanks for the heads up, the guy was insisting on using ternary and I made it work but I think his knowledge of types and polymorphism and pointer is not sufficient which led to asking this question. @273K – Shahrooz Apr 25 '23 at 18:46
  • @ShahroozLeon I think you didn't understand the question. There will be no object slicing here. The answer you suggested is also not correct. Using dynamic cast is really a overhead here and that too without checking outcome of dynamic_cast output here. My only concern was why its not working with ternary operator? – Rakesh Mehta Apr 26 '23 at 06:35
  • Because as I said and as it must be ternary operator only works with same type, I dont think you carefuly read what I wrote, youre trying something like this: int var = 1==2 ? "string" : 873144e+10; I think you don't have a sufficient understanding of basics of C++ especially with pointers when you try to get polymorphism through unique pointers. @RakeshMehta – Shahrooz Apr 26 '23 at 10:27
  • You might want to revisit it yourself. Using `dynamic_cast` to up cast is completely unneeded. You up cast with `static_cast` and down cast with `dynamic_cast` – NathanOliver Apr 26 '23 at 12:05
  • @ShahroozLeon I was unaware that ternary didn't support polymorphic types. I was assuming that a single if-else statement can be replaced by a ternary operator. The example you provide ```int var = 1==2 ? "string" : 873144e+10```will never work in simple if else block as well. You need to revisit your basics. Unique_ptr or using pointer/reference never cause in object slicing. – Rakesh Mehta Apr 26 '23 at 12:27
  • 1
    Error (active) E0042 operand types are incompatible ("CPostgreSQLDBAbstractFactory *" and "COracleDBAbstractFactory *") Error C2446 ':': no conversion from 'COracleDBAbstractFactory *' to 'CPostgreSQLDBAbstractFactory *' this is so clear to me to not ask from anyone else to explain it to me then I play and resist from acknowledging the fact that I made a very basic error. – Shahrooz Apr 26 '23 at 14:08