Ошибка ниже сбивает меня с толку. Вот небольшой фрагмент гораздо более сложного кода. Мне кажется странным, что только существование как шаблонного конструктора, так и виртуального метода вызывает ошибку, и только при инициализации объекта при копировании.
У кого-нибудь есть идея? Благодарю.
class A
{
long *p;
public:
A():p(0)
{
}
template<class T>
A(T val):p(val)// 1
{
}
operator long*()
{
return p;
}
};
class B
{
virtual void f()// 2
{
}
};
class C : public A, public B
{
};
void main()
{
C c;
Следующая строка в main()
является
A a=c;
и это вызывает ошибку ниже, если обе линии отмечены // 1
а также // 2
присутствуют:
warning C4717: 'C::C' : recursive on all control paths, function will cause runtime stack overflow
Но когда следующее используется в main()
нет ошибки:
A a;
a=c;
}
То, что у вас есть, это мерзкое слияние копия elision и конструктор, который делает копию параметра.
Во-первых, давайте проясним недоразумение: A a = c;
является не эквивалентно A a; a = c;
, Первый вызывает копию ctor, второй вызывает оператор присваивания. Смотрите сами, используя этот пример кода.
Конструктор A::A<T>(T)
может сделать копию T
всякий раз, когда это называется. К сожалению, если вы называете это с помощью A
параметр (или в вашем примере C
, который является A
), параметр попытается скопировать сам, который вызывает A::A<T>(T)
снова, который копирует себя снова и снова … до тех пор, пока стек не переполнится.
Почему этого не происходит, когда у вас нет virtual void f()
в B
? Это побочный эффект исключения из копирования, который зависит от реализации. Наличие виртуального метода могло бы быть достаточным для Visual Studio, чтобы решить не исключать копию, но в любом случае вы не должны зависеть от этого. Вот почему ты Настоятельно рекомендуется не иметь видимых побочных эффектов для копирующих ctors.
Если вы искали решение, вы можете удалить копию, изменив A::A<T>(T)
взять ссылку, как A::A<T>(T&)
, Еще лучше возьми const T&
потому что это помогает гарантировать отсутствие побочных эффектов в ctor (так как вы не можете изменить T
).
A a=c; // this results in A::A(C c) template constructor instantiation.
После этого это рекурсия, так как чтобы сделать копию, вам нужно сделать копию, вам нужно сделать копию …. 🙂
Для правильного использования обратитесь этот.