Cloneable & Auto-Cloneable, getting pure virtual errors

The initial problem in this first post has been solved, but I have another problem: http://www.cplusplus.com/forum/general/85526/#msg458740

I'm really pulling my hair out here because I can't see what I am doing wrong or why this shouldn't work.

http://ideone.com/4XY0ii

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
        struct Cloneable
        {
        protected:
                Cloneable(){}
                Cloneable(const Cloneable &){}
        public:
                virtual ~Cloneable(){}
 
                Cloneable &operator=(const Cloneable &) = delete;
 
                virtual Cloneable *Clone() const = 0;
                static void ReleaseClone(Cloneable *&clone)
                {
                        clone->ReleaseClone(), clone = /*nullptr*/0;
                }
        protected:
                virtual void ReleaseClone() = 0;
        public:
//              struct CloningException : public virtual Exception
//              {
//                      CloningException(){}
//                      CloningException(const char *msg) : Exception(msg) {}
//                      CloningException(const CloningException &) = delete;
//                      CloningException &operator=(const CloningException &) = delete;
//                      virtual ~CloningException(){}
//              };
 
                template<typename InheritingClass>
                struct Auto : public virtual Cloneable
                {
                        typedef InheritingClass ICT;
                        virtual ICT *Clone() const
                        {
                                const ICT *t = dynamic_cast<const ICT *>(this);
                                if(!t)
                                {
//                                      throw CloningException();
                                }
                                return new ICT(*t);
                        }
                protected:
                        virtual void ReleaseClone()
                        {
                                if(!dynamic_cast<const ICT *>(this))
                                {
//                                      throw CloningException();
                                }
                                delete this;
                        }
                public:
                        virtual ~Auto(){}
                };
        };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
struct MyAbstractClass : public virtual Cloneable
{
    MyAbstractClass(){}
protected:
    MyAbstractClass(const MyAbstractClass &){}
public:
    virtual ~MyAbstractClass(){}
    
    MyAbstractClass &operator=(const MyAbstractClass &) = delete;
 
    virtual void Tick() = 0;
};
 
struct MyImplementationClass : public virtual MyAbstractClass, public virtual Cloneable::Auto<MyImplementationClass>
{
    MyImplementationClass(){}
protected:
    MyImplementationClass(const MyImplementationClass &){}
public:
    virtual ~MyImplementationClass(){}
    
    MyImplementationClass &operator=(const MyImplementationClass &) = delete;
    
    virtual void Tick();
    
    using Cloneable::Auto<MyImplementationClass>::Clone;
protected:
    using Cloneable::Auto<MyImplementationClass>::ReleaseClone;
};
1
2
3
4
void MyImplementationClass::Tick()
{
    std::cout << "Tick" << std::endl;
}
1
2
3
4
5
6
7
int main()
{
    MyImplementationClass a;
    MyAbstractClass *b = a.Clone();
    b->Tick();
    Cloneable::ReleaseClone(b);
}
prog.cpp:32:3: error: invalid use of incomplete type 'struct Cloneable'
prog.cpp:4:2: error: forward declaration of 'struct Cloneable'
prog.cpp: In function 'int main()':
prog.cpp:94:27: error: cannot declare variable 'a' to be of abstract type 'MyImplementationClass'
prog.cpp:71:1: note:   because the following virtual functions are pure within 'MyImplementationClass':
prog.cpp:13:22: note: 	virtual Cloneable* Cloneable::Clone() const
prog.cpp:19:16: note: 	virtual void Cloneable::ReleaseClone()
prog.cpp:97:30: error: no matching function for call to 'Cloneable::ReleaseClone(MyAbstractClass*&)'
prog.cpp:14:15: note: candidates are: static void Cloneable::ReleaseClone(Cloneable*&)
prog.cpp:19:16: note:                 virtual void Cloneable::ReleaseClone()
prog.cpp: In member function 'ICT* Cloneable::Auto<InheritingClass>::Clone() const
[with InheritingClass = MyImplementationClass, ICT = MyImplementationClass]':
prog.cpp:95:34:   instantiated from here
prog.cpp:41:22: error: cannot allocate an object of abstract type 'MyImplementationClass'
prog.cpp:71:1: note:   since type 'MyImplementationClass' has pure virtual functions
I'm clearly stating that I am using the function implementations from Cloneable::Auto, but it still thinks that MyImplementationClass is abstract and has not implemented those functions. I also don't understand the first errors about Cloneable being incomplete...

I wrote all this code myself so I probably went about it in the wrong way, but this is what I had hoped worked, because otherwise this will be a nightmare to implement.

Edit: getting closer, but still not desirable: http://ideone.com/y5BGKH
Last edited on
You're not defining Cloneable::ReleaseClone?
I also don't understand the first errors about Cloneable being incomplete...


To quote clang++, whose compiler diagnostics make more sense:

test.cc:31:32: error: base class has incomplete type
                struct Auto : public virtual Cloneable
                              ~~~~~~~~~~~~~~~^~~~~~~~~
test.cc:3:12: note: definition of 'Cloneable' is not complete until the closing
      '}'
    struct Cloneable
           ^

And the return type of Auto::Clone doesn't match that of Cloneable. Auto::Clone has to return a pointer to a Cloneable or one of its subclasses.

EDIT: Wait! The problem must be something else because ICT is a subclass of Cloneable in your program.
Last edited on
Thanks all, I've done it*!

http://ideone.com/SC5HwT

It's not as elegant as I hoped, but I think I can tweak that.

*without the help of EssGeEich, who by the way is only partially incorrect.
Last edited on
@Peter87 I messed with that and it really doesn't like having the return type be a templated type for some reason.

This works:
1
2
3
4
5
6
7
8
9
10
11
12
    template<typename InheritingClass>
    struct Cloneable::Auto : public virtual Cloneable
    {
        virtual Cloneable *Clone() const
        {
            const InheritingClass *t = dynamic_cast<const InheritingClass *>(this);
            if(!t)
            {
//                    throw CloningException();
            }
            return new InheritingClass(*t);
        }
This doesn't:
1
2
3
4
5
6
7
8
9
10
11
12
    template<typename InheritingClass>
    struct Cloneable::Auto : public virtual Cloneable
    {
        virtual InheritingClass *Clone() const
        {
            const InheritingClass *t = dynamic_cast<const InheritingClass *>(this);
            if(!t)
            {
//                    throw CloningException();
            }
            return new InheritingClass(*t);
        }
http://ideone.com/on8Duk
prog.cpp: In instantiation of 'Cloneable::Auto<MyImplementationClass>':
prog.cpp:75:1:   instantiated from here
prog.cpp:41:34: error: invalid covariant return type for 'InheritingClass* Cloneable::Auto<InheritingClass>::Clone() const
                                                          [with InheritingClass = MyImplementationClass]'
prog.cpp:13:28: error:   overriding 'virtual Cloneable* Cloneable::Clone() const'
I'd like to know how to fix it, because otherwise it means I have to use a dynamic_cast on the clone function provided by Cloneable::Auto to get back down to the correct type - very ugly and unintuitive. It could be avoided if I implemented the clone function manually, but then what is the point of the automagical class that is supposed to do that for me?
Last edited on
So there's no good way? Using dynamic_cast or any cast on the return value of Clone is pretty ugly.
Last edited on
VC++ is good with either. Have you tried a newer version of GCC than is used by ideone?
cire wrote:
VC++ is good with either. Have you tried a newer version of GCC than is used by ideone?
Ah, that's good to know. I was on vacation and didn't have any access to a compiler so I couldn't test. Thanks!
Topic archived. No new replies allowed.