неявное преобразование при вызове по значению и полиморфизму

Рассмотрим следующий сценарий:
Некоторые полиморфные классы:

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

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, Однако все это не имеет прямого отношения к проблеме, описанной в вашем вопросе.

3

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru