Рассмотрим следующий сценарий:
Некоторые полиморфные классы:
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() { ... }
};
Кроме того, функция:
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;
}
Почему компилятор не разрешает преобразование из CommonClass в SpecificClass при первом вызове функции, хотя новый SpecificClass все равно создается по вызову, и для этого конкретного преобразования есть конструктор?
И почему я получаю это странное сообщение об ошибке? Вызов конструктора копирования без ссылки?
Кто-нибудь может поделиться некоторым пониманием этой проблемы?
Кстати, я должен использовать GCC 4.1.2
someFunc
требует аргумент типа SpecificClass
, и вы предоставляете один из типа CommonClass
, Поскольку вы определили конструктор преобразования
SpecificClass::SpecificClass(CommonClass &)
это преобразование может быть выполнено неявно, и это здорово.
[Заметьте, однако, что ваш конструктор преобразования использует неконстантную ссылку, которая работает здесь, потому что вы фактически предоставляете ему lvalue — однако, в общем, я бы предположил, что аргумент конструктора преобразования принимает какconst CommonClass &
обычно лучше (поскольку обычно не ожидается, что преобразование из одного типа в другой изменит оригинал).]
Тем не менее проблема происходит на следующем шаге: только что преобразованный объект типа SpecificClass
теперь нужно скопировать в аргумент функции sc
из someFunc
, Для этого вам нужен конструктор копирования для SpecificClass
который может принять значение (это то, что недавно преобразованный SpecificClass
объект есть, потому что он временный).
Ваш конструктор копий
SpecificClass::SpecificClass(SpecificClass &)
объявляется с использованием неконстантной ссылки lvalue, которая не может быть привязана к временной. Таким образом, вы должны изменить это в
SpecificClass::SpecificClass(const SpecificClass &)
решить проблему. И это обычный способ объявления конструктора копирования в любом случае.
Еще одна вещь, которую я не могу не заметить: у вас есть функция someFunc
это предназначено, чтобы быть вызванным на объектах только очень определенного типа. И все же вы называете это общим (базовым классом?) Типом. Понятно, что это можно сделать так, как вы описали, но во многих случаях это противоречит интуиции и не совсем соответствует принципу объектно-ориентированного программирования. Это также заставляет меня задуматься о том, как «конкретный» объект на самом деле создается из «общего», то есть того, что фактически делает конструктор преобразования. Интуитивно я бы предположил, что «общему» объекту, указанному в качестве входных данных, не хватает «конкретной» информации для создания «конкретного» объекта.
В любом случае, вы можете пересмотреть структуру иерархии классов и / или цель someFunc
, Однако все это не имеет прямого отношения к проблеме, описанной в вашем вопросе.
Других решений пока нет …