Philipp Michalski
Philipp Michalski

Reputation: 606

implicit conversion at call by value and polymorphism

Consider the following scenario: Some polymorphic classes:

struct iClass 
{
  virtual ~iClass(){} 
};
struct CommonClass : public iClass 
{
  char str[128];
  CommonClass() { ... }
  ...
};
struct SpecificClass : public iClass
{
  char str[32];
  SpecificClass () { ... }
  SpecificClass (SpecificClass& src) { strcpy(...); ... }
  SpecificClass (CommonClass& src) { strcpy(...); ... }
  SpecificClass (const CommonClass& src) { strcpy(...); ... }
  void foo() { ... }
};

Furthermore a function:

void someFunc(SpecificClass sc) { sc.foo(); } // pass by value: i want it copied!

int main ()
{
  CommonClass comCl;
  someFunc(comCl);  // <- Error: no matching function for call to 'SpecificClass::SpecificClass(SpecificClass)' NOTE: no &
  SpecificClass specCl(comCl);
  someFunc(specCl); // Works normal, but the str gets copied double times this way, isnt it?
  return 0;
}

Why does the compiler not allow the conversion from CommonClass to SpecificClass in the first function call although a new SpecificClass gets constructored on the call anyways and there is a constructor for this specific conversion? And why do i get this strange error message? A call to a copy constructor without a reference? Can anyone share some insight into this problematic?

Btw, i have to use gcc 4.1.2

Upvotes: 2

Views: 130

Answers (1)

jogojapan
jogojapan

Reputation: 69967

someFunc requires an argument of type SpecificClass, and you provide one of type CommonClass. Since you have defined a conversion constructor

SpecificClass::SpecificClass(CommonClass &)

this conversion can be performed implicitly, and that's great so far.

[Note, though, that your conversion constructor takes a non-const reference, which works here because you actually supply it with an lvalue – however, in general, I'd assume that taking the argument of the conversion constructor as const CommonClass & is usually better (since the conversion from one type into another isn't usually expected to alter the original).]

However, the problem occurs in the next step: The freshly converted object of type SpecificClass now needs to be copied into the function argument sc of someFunc. For this you need a copy constructor for SpecificClass which can take an rvalue (that's what the freshly converted SpecificClass object is, because it's a temporary).

Your copy constructor

SpecificClass::SpecificClass(SpecificClass &)

is declared to take a non-const lvalue reference, which can't bind to the temporary. So you must change this into

SpecificClass::SpecificClass(const SpecificClass &)

to fix the problem. And that's the usual way of declaring a copy constructor anyway.


One other thing I can't help noticing: You have a function someFunc that is meant to be called on objects of a very specific type only. Yet you call it on a general (base class?) type. Clearly, this can be made to work in the way you described, but it is in many ways counter-intuitive and not well-aligned with the principle of object-oriented programming. It also makes me wonder how the 'specific' object is actually created from the 'common' one, i.e. what the conversion constructor actually does. Intuitively, I'd assume the 'common' object given as input lacks the 'specific' information to create a 'specific' object.

In any case, you may want to reconsider the structure of your class hierarchy and/or the purpose of someFunc. None of this is directly related to the problem described in your question, though.

Upvotes: 3

Related Questions