Thread: Unable to store child class in parent class declaration

  1. #1
    Registered User
    Join Date
    Mar 2022
    Posts
    9

    Angry Unable to store child class in parent class declaration

    Hello,

    Can anyone explain what's wrong with below code:
    Code:
    #include <iostream>
    #include <vector>
    
    
    using namespace std;
    
    
    class A
    {
    public:
        virtual int get() = 0;
    };
    
    
    class B : public A
    {
    public:
        int get() { return 0; };
    };
    
    
    int main()
    {
        std::vector<A> v;
    
    
        B b;
        v.push_back(b);
    };
    And throws this error:
    Code:
    /usr/bin/g++ -pthread --std=c++17 -fdiagnostics-color=always -g /home/test/*.cpp -o /home/test/main
    In file included from /usr/include/x86_64-linux-gnu/c++/9/bits/c++allocator.h:33,
                     from /usr/include/c++/9/bits/allocator.h:46,
                     from /usr/include/c++/9/string:41,
                     from /usr/include/c++/9/bits/locale_classes.h:40,
                     from /usr/include/c++/9/bits/ios_base.h:41,
                     from /usr/include/c++/9/ios:42,
                     from /usr/include/c++/9/ostream:38,
                     from /usr/include/c++/9/iostream:39,
                     from /home/test/main.cpp:1:
    /usr/include/c++/9/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = A; _Args = {const A&}; _Tp = A]’:
    /usr/include/c++/9/bits/alloc_traits.h:482:2:   required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = A; _Args = {const A&}; _Tp = A; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<A>]’
    /usr/include/c++/9/bits/stl_vector.h:1189:30:   required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = A; _Alloc = std::allocator<A>; std::vector<_Tp, _Alloc>::value_type = A]’
    /home/test/main.cpp:24:18:   required from here
    /usr/include/c++/9/ext/new_allocator.h:145:20: error: invalid new-expression of abstract class type ‘A’
      145 |  noexcept(noexcept(::new((void *)__p)
          |                    ^~~~~~~~~~~~~~~~~~
      146 |        _Up(std::forward<_Args>(__args)...)))
          |        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /home/test/main.cpp:7:7: note:   because the following virtual functions are pure within ‘A’:
        7 | class A
          |       ^
    /home/test/main.cpp:10:17: note:   ‘virtual int A::get()’
       10 |     virtual int get() = 0;
          |                 ^~~
    
    
    Build finished with error(s).

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,376
    You need to use pointers (or references) to get polymorphism.
    Code:
    #include <iostream>
    #include <vector>
    using namespace std;
     
    class A
    {
    public:
        virtual ~A() {}
        virtual int get() const = 0;
    };
     
    class B : public A
    {
    public:
        int get() const override { return 0; };
    };
     
    int main()
    {
        std::vector<A*> v;
        v.push_back(new B);
     
        cout << v.back()->get() << '\n';
     
        for (auto p: v) delete p;
    }
    A long time ago being crazy meant something. - Charles Manson

  3. #3
    Registered User
    Join Date
    Mar 2022
    Posts
    9
    Quote Originally Posted by john.c View Post
    You need to use pointers (or references) to get polymorphism.
    Code:
    #include <iostream>
    #include <vector>
    using namespace std;
     
    class A
    {
    public:
        virtual ~A() {}
        virtual int get() const = 0;
    };
     
    class B : public A
    {
    public:
        int get() const override { return 0; };
    };
     
    int main()
    {
        std::vector<A*> v;
        v.push_back(new B);
     
        cout << v.back()->get() << '\n';
     
        for (auto p: v) delete p;
    }
    Thank you so much, it worked for me. But is that necessary to add const and override in B class?

  4. #4
    Registered User
    Join Date
    Dec 2017
    Posts
    1,376
    It depends on what you mean by "necessary". As for 'override', maybe you can forget about that for now. It just ensures that the function is overriding something (as opposed to being misspelled, for example).

    As for "const", if a method does not modify the state of the object then it should be declared const so that the compiler knows it can use the method in contexts where the object is const.

    So in the example below, if you removed 'const' from all of the get() methods (including the base class A) then function f(), which accepts const A&, won't be able to call get() even though get() doesn't change the state of the object.
    Code:
    #include <iostream>
    #include <vector>
    using namespace std;
     
    class A
    {
    public:
        virtual ~A() {}
        virtual int get() const = 0;
    };
     
    class B : public A
    {
    public:
        int get() const { cout << "B: "; return 0; };
    };
     
    class C : public A
    {
    public:
        int get() const { cout << "C: "; return 0; };
    };
     
    // f() promises not to modify 'a'.
    // So it will only be allowed to call 'const' methods on 'a'.
    void f(const A& a) { cout << a.get() << '\n'; }
     
    int main()
    {
        std::vector<A*> v;
        v.push_back(new B);
        v.push_back(new C);
        v.push_back(new C);
        v.push_back(new B);
     
        for (const auto p: v) f(*p);
     
        for (auto p: v) delete p;
        v.clear();
    }
    Last edited by john.c; 03-05-2022 at 07:00 PM.
    A long time ago being crazy meant something. - Charles Manson

  5. #5
    Registered User
    Join Date
    Sep 2020
    Posts
    136
    BTW. According to C++ guidelines raw pointers should not be used.
    C++ Core Guidelines
    So a better option is to use either std::unique_ptr or std::shared_ptr.

    For a kind of static polymorphism std::variant would be an option.

  6. #6
    Registered User
    Join Date
    Mar 2022
    Posts
    9
    Quote Originally Posted by john.c View Post
    It depends on what you mean by "necessary". As for 'override', maybe you can forget about that for now. It just ensures that the function is overriding something (as opposed to being misspelled, for example).

    As for "const", if a method does not modify the state of the object then it should be declared const so that the compiler knows it can use the method in contexts where the object is const.

    So in the example below, if you removed 'const' from all of the get() methods (including the base class A) then function f(), which accepts const A&, won't be able to call get() even though get() doesn't change the state of the object.
    Code:
    #include <iostream>
    #include <vector>
    using namespace std;
     
    class A
    {
    public:
        virtual ~A() {}
        virtual int get() const = 0;
    };
     
    class B : public A
    {
    public:
        int get() const { cout << "B: "; return 0; };
    };
     
    class C : public A
    {
    public:
        int get() const { cout << "C: "; return 0; };
    };
     
    // f() promises not to modify 'a'.
    // So it will only be allowed to call 'const' methods on 'a'.
    void f(const A& a) { cout << a.get() << '\n'; }
     
    int main()
    {
        std::vector<A*> v;
        v.push_back(new B);
        v.push_back(new C);
        v.push_back(new C);
        v.push_back(new B);
     
        for (const auto p: v) f(*p);
     
        for (auto p: v) delete p;
        v.clear();
    }
    Much clear, thanks again.

  7. #7
    Registered User
    Join Date
    Mar 2022
    Posts
    9
    Same as I'm trying another example, it causing similar kind of issue: (In actual I have different classes names)
    Code:
    // Product.h
    class Product
    {
    };
    
    // Category.h
    #include "Product.h"
    
    enum MyType
    {
        AAA,
        BBB
    };
    
    class Category
    {
    public:
        virtual int getX(Product) = 0;
        virtual void printX(Product) = 0;
    };
    
    class CategoryImpl : public Category
    {
    public:
        void printX(Product &p);
    };
    
    template <MyType t>
    class CategoryImplType : public CategoryImpl
    {
    };
    
    template <>
    class CategoryImplType<AAA> : public CategoryImpl
    {
    public:
        int getX(Product &p);
    };
    template <>
    class CategoryImplType<BBB> : public CategoryImpl
    {
    public:
        int getX(Product &p);
    };
    
    // Category.cpp
    #include "Category.h"
    #include "string"
    
    void CategoryImpl::printX(Product &p)
    {
        // ...
    }
    int CategoryImplType<AAA>::getX(Product &p)
    {
        return 0;
    }
    int CategoryImplType<BBB>::getX(Product &p)
    {
        return 1;
    }
    
    // main.cpp
    #include "Category.h"
    
    using namespace std;
    
    int main()
    {
        CategoryImplType<AAA>(); // Error on this line shown below:
        /* template<> class CategoryImplType<AAA>
           a cast to abstract class "CategoryImplType<AAA>" is not allowed:C/C++(389)
           main.cpp(8, 5): pure virtual function "Category::getX" has no overrider
           main.cpp(8, 5): pure virtual function "Category::printX" has no overrider
        */
    };
    If I remove the reference sign from getX() & printX() function like only getX(Product p) then it works fine but with & throwing error.
    Last edited by 2k10cs86; 03-06-2022 at 02:54 AM.

  8. #8
    Registered User
    Join Date
    Dec 2017
    Posts
    1,376
    You need to put & into the declarations in Category.
    Code:
    class Category
    {
    public:
        virtual int getX(Product &) = 0;
        virtual void printX(Product &) = 0;
    };
    A long time ago being crazy meant something. - Charles Manson

  9. #9
    Registered User
    Join Date
    Mar 2022
    Posts
    9
    Quote Originally Posted by john.c View Post
    You need to put & into the declarations in Category.
    Code:
    class Category
    {
    public:
        virtual int getX(Product &) = 0;
        virtual void printX(Product &) = 0;
    };
    Thanks for the answer, much appreciated. I have still concern with above example, if I call the getX(...) function in printX(...) then I'm getting error undefined reference:

    Code:
    // Category.cpp
    void CategoryImpl::printX(Product p) const
    {
        std::cout << CategoryImpl::getX(p);
    }
    
    // main.cpp
    int main()
    {
        Category *obj = new CategoryImplType<AAA>();
        obj->printX(Product()); // Error below:
    
        /*/usr/bin/ld: /tmp/ccEjMMob.o: in function `CategoryImpl::printX(Product) const':/home/test/cat.cpp:7: undefined reference to `Category::getX(Product) const'
    collect2: error: ld returned 1 exit status
       */
    };

  10. #10
    Registered User
    Join Date
    Dec 2017
    Posts
    1,376
    It should be more like this:
    Code:
    void CategoryImpl::printX(const Product &p) const
    {
        std::cout << getX(p) << '\n';
    }
    The main problem was CategoryImpl:: before getX. I also changed it to a reference (Product &) and added const. You need to ensure that previous declarations of printX look the same.
    A long time ago being crazy meant something. - Charles Manson

  11. #11
    Registered User
    Join Date
    Mar 2022
    Posts
    9
    Quote Originally Posted by john.c View Post
    It should be more like this:
    Code:
    void CategoryImpl::printX(const Product &p) const
    {
        std::cout << getX(p) << '\n';
    }
    The main problem was CategoryImpl:: before getX. I also changed it to a reference (Product &) and added const. You need to ensure that previous declarations of printX look the same.
    That's much clear, thanks for saving my days.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Cast a parent class to child
    By snowcore in forum C# Programming
    Replies: 12
    Last Post: 03-04-2011, 10:02 AM
  2. Can Nested class access parent class's private member?
    By meili100 in forum C++ Programming
    Replies: 4
    Last Post: 06-05-2009, 08:42 AM
  3. gcc: Template class child can't directly access parent fields
    By SevenThunders in forum C++ Programming
    Replies: 11
    Last Post: 03-17-2009, 06:05 AM
  4. Replies: 2
    Last Post: 04-06-2005, 07:25 AM
  5. A little question on template parent/child class...
    By JamesW in forum C++ Programming
    Replies: 1
    Last Post: 05-08-2003, 06:39 PM

Tags for this Thread