0

I have two classes with similar structure.

class A{
    int a;
    char *b;
    float c;
    A(char *str) { //allocate mem and assign to b }
};

class B{
    int a;
    char *b;
    float c;
    B(char *str) { //allocate mem and assign to b }
    B(B & bref) { //properly copies all the data }
};

I want to copy an object of B to the object of A. Are the following conversions fine?

A aobj("aobjstr");
B bobj("bobjstr");
bobj = aobj;    //case 1
bobj = B(aobj); //case 2

Will the case 2 work? Will aobj be properly converted and interpreted as B & when B's copy constructor gets called?

EDIT: What about?

B bobj(aobj)
krips89
  • 1,683
  • 4
  • 17
  • 32
  • 1
    First of all, that's not the copy constructor being called. You already constructed it before. Secondly, if it was, it would give an error because of the non-const reference to a temporary. – chris Feb 21 '13 at 07:15
  • 2
    Have you tried? U will likely get errors, why dont you inherit from a common class? – Karthik T Feb 21 '13 at 07:15
  • Do you already know C# or Java? If so, that would explain a probably misunderstanding here - in particular the line `bobj = B(aobj)`, which actually constructs a temporary object, copies (or attempts to copy - no assignment overload shown) from the temporary to `bobj`, then discards the temporary. Reason is basically that `bobj` is the actual object, not (as it would be in Java) a reference to the object. –  Feb 21 '13 at 07:22
  • @Karthick T, I can't change/modify class A and B, those are generated. Also I don't want to write a function to copy one class to other manually. – krips89 Feb 21 '13 at 07:24
  • Without proper assignment and/or alternate construction provisions, the specified code is not only not fine, it won't even *compile* (which should have been a first clue). – WhozCraig Feb 21 '13 at 07:40
  • The down-vote arrow has the text `"doesn't show research effort"`, tempted to click it. – Peter Wood Feb 21 '13 at 08:14
  • @PeterWood, yes I didn't compile it myself that was a mistake I guess. But I was looking for reasons of what would/wouldn't work and how. – krips89 Feb 21 '13 at 09:48

3 Answers3

2

No, you can't implicitly convert between unrelated types without writing conversion constructors or conversion operators. Presumably, your compiler told you this; mine gave errors such as:

error: no match for ‘operator=’ in ‘bobj = aobj’
note:  no known conversion for argument 1 from ‘A’ to ‘const B&’
error: no matching function for call to ‘B::B(A&)’

You could allow the conversion by giving B a conversion constructor:

class B {
    // ...
    B(A const & a) { /* properly copy the data */ }
};

If you can't change the classes, then you'll need a non-member function to do the conversion; but this is probably only possible if the class members are public. In your example, all the members, including the constructors, are private, so the classes can't be used at all. Presumably, that's not the case in your real code.

If you want to live dangerously, you might be able to get away with explicitly reinterpreting an A object as a B, since they are both standard-layout types with the same data members:

// DANGER: this will break if the layout of either class changes
bobj = reinterpret_cast<B const &>(a);

Note that, since your class allocates memory, it presumably needs to deallocate it in its destructor; and to avoid double deletions, you'll also have to correctly implement both a copy constructor and a copy-assignment operator per the Rule of Three.

If that all sounds like too much work, why not use std::string, which takes care of memory management for you?

Community
  • 1
  • 1
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Thank you! This is very precise. I am curious about your statement 'since they are both standard-layout types with the same data members, reinterpret_cast will work'. I tried looking for documentation on reinterpret_cast didn't find the exact specification and working. Can you point me to a detailed documentation source? BTW, I pretty much don't know about the the nature of class A and B. It may not contain floating pointers to other object. I included it trying to cover up everything in a minimal example. – krips89 Feb 21 '13 at 09:40
  • @krips89: In the C++11 standard, `reinterpret_cast` is defined in 5.2.10 (particularly clauses 7 and 11 for pointers or references to standard-layout types); standard-layout classes are defined in 9/7; and layout-compatible classes in 9.2/17. But you'd be well advised not to use it, since it could break, with no errors or warnings, if the class layout changed. – Mike Seymour Feb 21 '13 at 10:24
2

If you tried to compile it you would find that none of this works. For one thing your constructors are private.

bobj = aobj;    //case 1

This tries to call an assignment operator with the signature:

B& B::operator =(A const&)

This does not exist and compilation will fail.

bobj = B(aobj); //case 2

This tries to call A::operator B(), which does not exist and compilation will fail.

Finally:

B bobj(aobj)

This tries to call a constructor with the signature B::B(A const&), which does not exist and compilation will fail.

You say,

I can't change/modify class A and B, those are generated.

Then either the generator needs to be fixed or you're going to have to write your own adaptors.

johnsyweb
  • 136,902
  • 23
  • 188
  • 247
0

You can do this by considering the following notes:

1) char* b makes a problem. When you copy aobj to bobj, the value of pointer aobj.b will be copied to bobj.b which means that they both refer to a same memory location and changing one like this: aobj.b[0] = 'Z' will cause bobj.b to change.

You can solve this by changing b from a pointer to a flat array:

//...
char b[MAXLEN];
//...

The better solution to this is to define a constructor (accepting the other type) and overload the assignment (=) operator, at least for class B, and handle the pointer assignment (allocate buffer for the new pointer and copy content to it).

2) UPDATED: A sample syntax is like this:

   bobj = B(reinterpret_cast<B&> (aobj));

   // or simply:
   bobj = reinterpret_cast<B&> (aobj);

3) Note that this is dangerous, not safe, and not recommended. This means that the design of your solution should probably change. For example, A and B may both inherit from a common base class; B inherits from A; or B explicitly defines a constructor and an assignment operator for class A. These are far more recommended.

Masood Khaari
  • 2,911
  • 2
  • 23
  • 40