1

An abstract class has internal virtual functions. Can an abstract class have internal virtual classes to be implemented later?

I tried the following:

#include <bits/stdc++.h>
using namespace std;

class C1 {
    public:
        class Child {
            int tmp;
            virtual int getint() = 0;
        };
    virtual Child getChild() = 0;
};

class C2: public C1 {
    public:
        class Child {
            int getint()
            {
                return 10;
            }
        } c;
    Child getChild()
    {
        return c;
    }
};

int main() { return 0; }

Child is an abstract class which will be overrode in derived classes. And I hope the implemented Child can be used to define a function.

However, I got an error:

invalid abstract return type for member function 'virtual C1::Child C1::getChild()'

Can't I implement an internal abstract class in derived classes, just like implementing a virtual function?

Zehui Lin
  • 186
  • 9
  • This doesn't have anything to do with internal classes. You can greatly simplify your example. Here's a [mcve]: `struct foo { virtual stuff() = 0; }; foo make_foo();`. – juanchopanza Jan 03 '17 at 09:32
  • You cannot return abstract objects as value. If you do that, how can the client use it as there are missing implementations for `pure virtual` functions?. You can however return pointer to such object. Additionally: in your example `Child` is not abstract. Edit it as someone may not understand your problem. – Michał Walenciak Jan 03 '17 at 09:34
  • @MichałWalenciak Clients call the virtual functions defined in that abstract class. – Zehui Lin Jan 03 '17 at 09:45
  • @ZehuiLin: I know, but as you have returned 'incomplete' object, how can it work? :) – Michał Walenciak Jan 03 '17 at 09:49
  • The only difference between a class defined inside another class and one that isn't is the scope of their names. You have two unrelated classes; `C1::Child` and `C2::Child`. – molbdnilo Jan 03 '17 at 10:04

3 Answers3

2

In the present code, class C1::Child and class C2::Child have no inheritance relationship. Hence they are totally unrelated classes. Even if you relate them with inheritance, then also getChild() cannot return Child (value). It can return either Child& (reference) or Child* (pointer) to form a valid virtual methods with covariance. Refer: C++ virtual function return type

Such errors are easily caught by using override specifier available in C++11.

Without knowing the exact context of what you are trying to achieve, the possible code should look like this:

class C1 {
  // ... same
  virtual Child& getChild() = 0;
  //      ^^^^^^ reference
};

class C2 : public C1 {
//         ^^^^^^ did you miss this?
public:
  class Child : public C1::Child {
  //                   ^^^^^^^^^ inheritance
    int getint() override { return 10; }
  } c;
  Child& getChild() override { return c; }
};

Also your below statement seems confusing:

"Child is a abstract class, which will be implemented later,"

Like virtual methods, the classes don't have such runtime relationships.
The best meaning of "implementing later" in the context of class is -- implementing it outside the body of the enclosing class, such as:

class Outer { public: class Inner; };
// ...
class Outer::Inner { ... };
Community
  • 1
  • 1
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • So virtual functions and abstract class and treated different? I can call a virtual function, but I can not use an abstract class? – Zehui Lin Jan 03 '17 at 09:42
  • 1
    @ZehuiLin, I am unclear about your exact Qn. However, abstract classes are the classes with at least 1 pure `virtual` method inside their body. The `virtual` method is invoked using a base class reference or pointer. If the base class is abstract, then you cannot have its object. I would suggest to put some examples, if it's unclear to you. Refer this for more details on Abstract classes: [Abstract Class vs Interface in C++](http://stackoverflow.com/q/12854778/514235) – iammilind Jan 03 '17 at 09:47
1

Theoretically, Abstract Classes are used for creating Interfaces. Using Interfaces, clients demand the required functionality. By defining/implementing Interfaces, servers fulfill the client's functionality. Interface/Abstract Class are simply blueprint of requirement/agreement between client and server. The classes which implement the Interface/Abstract Class or fulfills the functionality requirement can be instantiated. So there can be many implementation of the same Interface/Abstract Class. Now in order to access all these different implementation of the same Interface/Abstract Class seamlessly at different point of time, we need a generalized way. And this generalized way is via pointer(*) or reference(&) to the underlying Interface\Abstract Class.

In your code C1::Child is an anAbstract Class or Interface.

So, C1::getChild() can return an implementation of the Interface/Abstract C1::Child. But it cannot return an instance of the Interface/Abstract C1::Child itself as per above theoretical explanation. And hence the error. Proper way to declare C1::getChild() would be:

  • virtual C1::Child* getChild() = 0; or
  • virtual C1::Child& getChild() = 0;

Also, C1::Child can be simply seen as a class inside namespace C1, since class is also a kind of namespace with some restriction.

sameerkn
  • 2,209
  • 1
  • 12
  • 13
0

From your post you seem to be confusing things. I suggest you get a re-read on abstract classes and try some simple examples yourself.

Child is a abstract class, which will be implemented later, And I hope the implemented Child can be used to define a function.

A pure virtual method (virtual int getint() = 0; in your example) is not meant to be implemented "later". It's meant to be implemented by an override method in a derived class.

E.g. if you have

class Child {
   virtual int getint() = 0;
};

you cannot do

class Child {
   virtual int getint() { return 10; }
};

nor

int Child::getint() { return 10; }

at a later time.

What you can do is:

class Derived : public Child
{
   int getint() override { return 10; }
};
bolov
  • 72,283
  • 15
  • 145
  • 224