conversion to non-scalar type error in inheritance hierarchy

K

kmw

Hello,

I am working on container class with different implementations and
want to add stl-style iterators. Now, I am confronted with a
"conversion to non-scalar type" error which I do not understand. Any
comments are appreciated. Many thanks in advance!

The interface for the different implementations is defined in the base
class A. A1 is one implementation. B is the iterator base class and C
its implementation in A1. I really do not see a problem since C
inherits from B but the compiler says:

test.cpp: In function ‘int main()’:
test.cpp:34: error: conversion from ‘A<int>::B’ to non-scalar type
‘A1<int>::C’ requested

Best regards,
Kay

Code:
template <class X>
class A
{
public:
class B
{
public:
virtual ~B () {}
virtual void method () {}
};
virtual ~A () {}
virtual B begin ()=0;
};
template <class X>
class A1 : public A<X>
{
public:
class C : public A<X>::B
{
public:
~C () {}
void method ( ) {}
};
~A1 () {}
typename A<X>::B begin ( )
{
C test;
return test;
}
};
int main ( )
{
A1<int> test;
A1<int>::C test_it = test.begin ();

return 0;
}
 
V

Victor Bazarov

kmw said:
Hello,

I am working on container class with different implementations and
want to add stl-style iterators. Now, I am confronted with a
"conversion to non-scalar type" error which I do not understand. Any
comments are appreciated. Many thanks in advance!

The interface for the different implementations is defined in the base
class A. A1 is one implementation. B is the iterator base class and C
its implementation in A1. I really do not see a problem since C
inherits from B but the compiler says:

test.cpp: In function ‘int main()’:
test.cpp:34: error: conversion from ‘A<int>::B’ to non-scalar type
‘A1<int>::C’ requested

You do not see the problem? How about here:

class B {};
class C : public B {};

B foo();

int main()
{
C c = foo();
}

Do you get the same error?
Best regards,
Kay

Code:
template <class X>
class A
{
public:
class B
{
public:
virtual ~B () {}
virtual void method () {}
};
virtual ~A () {}
virtual B begin ()=0;
};
template <class X>
class A1 : public A<X>
{
public:
class C : public A<X>::B
{
public:
~C () {}
void method ( ) {}
};
~A1 () {}
typename A<X>::B begin ( )
{
C test;
return test;
}
};
int main ( )
{
A1<int> test;
A1<int>::C test_it = test.begin ();

return 0;
}

There is no conversion from the base class to the derived class. You
have to define this conversion if you want it to exist.

V
 
K

kmw

Well, yes. Your code gives me the same error. I see the conversion
problem now. Thanks for clarifying. Of course I don't want explicit
conversion from the base class into the inherited classes. But how can
I achieve such kind of "parallel" inheritance? That is, 'C' is
accepted as 'B' in 'A1'. I know I could do it with reference returns
but that's not in accordance to the stl-iterator approach.

Cheers,
Kay
 
A

Alf P. Steinbach

* kmw:
Hello,

I am working on container class with different implementations and
want to add stl-style iterators.

It may be easiest to write a templated wrapper that uses some underlying
conventional named methods interface to provide STL iterator functionality.

Now, I am confronted with a
"conversion to non-scalar type" error which I do not understand. Any
comments are appreciated. Many thanks in advance!

The interface for the different implementations is defined in the base
class A. A1 is one implementation. B is the iterator base class and C
its implementation in A1. I really do not see a problem since C
inherits from B but the compiler says:

test.cpp: In function ‘int main()’:
test.cpp:34: error: conversion from ‘A<int>::B’ to non-scalar type
‘A1<int>::C’ requested

Best regards,
Kay

Code:
template <class X>
class A
{
public:
class B
{
public:
virtual ~B () {}
virtual void method () {}
};
virtual ~A () {}
virtual B begin ()=0;
};
template <class X>
class A1 : public A<X>
{
public:
class C : public A<X>::B
{
public:
~C () {}
void method ( ) {}
};
~A1 () {}
typename A<X>::B begin ( )
{
C test;
return test;
}

Not related to the compilation error, but a logical error: this begin() function
always produces an A<X>::B object. It doesn't matter that that object is
initialized from a C object. When it's returned it's a B object, and calls to
method will invoke B::method.

};
int main ( )
{
A1<int> test;
A1<int>::C test_it = test.begin ();

test.begin() produces a B object. Class C does not provide any constructor that
takes a B object. A B object cannot be implicitly converted down to the more
specialized C object (the inheritance goes the wrong way).

return 0;
}


Cheers & hth.,

- Alf
 
K

kmw

It may be easiest to write a templated wrapper that uses some underlying
conventional named methods interface to provide STL iterator functionality.

Thanks for the hint. Could you give a small code snippet to ease my
understanding? That would be great!

I see the problem with the inheritance 'in the wrong way' now. Also,
thanks for this.

Cheers,
Kay
 
J

James Kanze

I am working on container class with different implementations
and want to add stl-style iterators. Now, I am confronted with
a "conversion to non-scalar type" error which I do not
understand. Any comments are appreciated. Many thanks in
advance!
The interface for the different implementations is defined in
the base class A. A1 is one implementation. B is the iterator
base class and C its implementation in A1. I really do not see
a problem since C inherits from B but the compiler says:
test.cpp: In function ‘int main()’:
test.cpp:34: error: conversion from ‘A<int>::B’ to non-scalar type
‘A1<int>::C’ requested
Code:
template <class X>
class A
{
public:
class B
{
public:
virtual ~B () {}
virtual void method () {}
};
virtual ~A () {}
virtual B begin ()=0;
};
template <class X>
class A1 : public A<X>
{
public:
class C : public A<X>::B
{
public:
~C () {}
void method ( ) {}
};
~A1 () {}
typename A<X>::B begin ( )
{
C test;
return test;
}
};
int main ( )
{
A1<int> test;
A1<int>::C test_it = test.begin ();
return 0;
}

You'll get the same problems without the iterators. The most
obvious problem (and why the compiler is complaining) is that
you're returning a A::B, and trying to use it to initialize an
A1::C; you can't normally use a base type to initialize a
derived type. The obvious solution for this is to use covariant
return types, except that covariant returns only work with
pointers and references, not with values.

Which brings us to the more general problem: Once A1::begin has
returned an A::B, all you have is an A::B---slicing has occured.
More generally, polymorphism only works through references or
pointers (and polymorphic classes should not generally be copied
or assigned). If you want the returned iterator to behave
polymorphically, you'll have to use some variant of the
letter/envelope or the handle idiom; for STL semantics, you'll
need deep copy, which will make copying iterators expensive.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top