Virtual Inner Classes?

In C++, inner classes are just classes in the scope of another class. In Java, there are inner classes which can only be instantiated from their outer class, and static inner classes, which are the same as C++ inner classes. Hoever, despite both languages being very OO and having virtual inheritence/polymorphism, neither allows virtual inner classes. What I mean by this is, for instance, class A has an inner class B, and clas C extends/inherits from class A. Both C++ and Java allow class C to give virtual function definitions for the virtual functions in class A, but neither language allows for giving virtual definitions for the functions in class B.

Is there a language where a class can implement virtual methods of its base classes' inner classes?
In Java, there are inner classes which can only be instantiated from their outer class
1
2
3
4
class outer{
private:
  class inner{};
};


neither language allows for giving virtual definitions for the functions in class B
¿Can't just derive from the inner class?
> In C++, inner classes are just classes in the scope of another class.

AFAIK, C++ has no notion of 'inner' classes - a type may be defined at any scope, including the global unnnamed namespace scope.

A type defined inside the scope of another type can have an access specifier which restricts access to the type. A type defined in an anonymous namespace is not programmatically visible outside the translation unit. A type defined in a local scope in a function is not programmatically visible outside that local scope. There are no other restrictions (C++11); a type defined in a local scope in a function cannot be used to instantiate a template (C++98).

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
#include <iostream>
#include <memory>

namespace one
{
    struct A
    {
        struct B
        {
            virtual ~B() noexcept {}
            virtual void foo() = 0 ;
        };

        std::shared_ptr<B> bar(bool) ;
    };

    std::shared_ptr<A::B> A::bar( bool f )
    {
        struct C : A::B
        {
            C( int, int ) {}
            virtual void foo() override { std::cout << "one::A::bar::C::foo\n" ; }
        };

        if(f) return std::make_shared<C>( 3, 4 ) ;

        else
        {
            struct D : C
            {
                D( int a, int b, int c ) : C(a,b) {}
                virtual void foo() override { std::cout << "one::A::bar::D::foo\n" ; }
            };
            return std::make_shared<D>( 10, 20, 30 ) ;
        }
    }
}


int main()
{
    one::A a ;
    auto p = a.bar(false) ;
    p->foo() ; // prints one::A::bar::D::foo
}



What compiler are you using for C++11 stuff?
GCC 4.7.0 - FreeBSD port of the 28 Jan 2012 snapshot
Thanks.
This is best explained in Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A
{
    public /*static*/ class B
    {
        public void print()
        {
            System.out.println("A.B.print()");
        }
    }
}
class C extends A
{
    public /*static*/ class B
    {
        public void print()
        {
            System.out.println("C.B.print()");
        }
    }
}
1
2
3
4
//if A.B and C.B are static:
A a = new C();
a.B b = new a.B();
b.print(); //prints "A.B.print()" even though 'a' is an instanceof C 
1
2
3
4
5
//if A.B and C.B are not static
A a = new C();
a.B b = a.new B();
b.print(); //prints "A.B.print()" even though 'a' is an instanceof C
           //and b was constructed from 'a' 
I hope the concept I am trying to show makes sense...
¿So what is the deal with the inner class then?
The 'object' created has no relationship with its creator, ¿is it just a matter of syntaxis?
The intent is for C.B to be to A.B as C.someVirtualMethod() is to A.someVirtualMethod()
The problem with that is that virtual function calls are resolved at runtime, whereas types need to be resolved at compile time.

C.B and A.B could be different sizes, have different vtables, etc, etc. So any code that uses A.B wouldn't be able to compile because it doesn't know how much space to allocate or how to use the object.

I would be suprised if this worked in any static typed language. Doesn't seem like it'd be a big deal for dynamic typed languages though.
Disch wrote:
Doesn't seem like it'd be a big deal for dynamic typed languages though.
LB wrote:
Is there a language where [...]?
This is hard to explain so I'm asking because it's hard to search for...
If I were more familiar with dynamic typed languages, I might know of one =( Sorry.
Well, thanks anyway. The closest I could get was Java's Reflection API.
In Scala you can inherit and override types. So this might be close.
I still fail to understand what the basic issue is. Why can't this be done (in effect) in C++ and I suppose a host of other similar languages? For example, like this (if it is so desperately needed for some particular reason; in general CRTP would be the preferred C++ technique - it is far more flexible):

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
#include <iostream>
#include <typeinfo>

struct base
{
    virtual ~base() {}

    struct nested
    {
        virtual ~nested() {}
        virtual const char* who_are_you() const
        { return typeid(*this).name() ; }
        virtual const char* have_you_overrridden_anything() const
        { return "NO, this is base::nested" ; }
    };

    virtual nested* create_nested() const { return do_create_nested() ; }
    static nested* do_create_nested() ;
};

base::nested* base::do_create_nested() { return new nested() ; }

struct derived : base
{
    virtual nested* create_nested() const { return do_create_nested() ; }
    static nested* do_create_nested() ;

    private:
        struct nested : base::nested
        {
            virtual const char* have_you_overrridden_anything() const
            { return "YES, this is derived::nested" ; }
        };
};

base::nested* derived::do_create_nested() { return new nested() ; }

int main()
{
    enum { N = 4, M = 6 } ;
    base* a[N] = { new base(), new derived(), new derived(), new base() } ;
    base::nested* b[M] = { derived::do_create_nested(), base::do_create_nested() } ;

    for( int i=0 ; i<N ; ++i ) b[i+2] = a[i]->create_nested() ;
    for( int i=0 ; i<N ; ++i ) delete a[i] ;

    for( int i=0 ; i<M ; ++i )
        std::cout << i << ". " << b[i]->who_are_you()
                        << "\n\t and have you overridden anything? "
                        << b[i]->have_you_overrridden_anything() << "\n\n" ;

    for( int i=0 ; i<M ; ++i ) delete b[i] ;
}


Last edited on
I am aware that it can be done with a 'create instance' method, but I was more interested in dynamic typed languages with OOP concepts :)
Python:
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
class A :
	def __init__( self, some_class, some_data ) :
		self.the_class = some_class
		self.the_data = some_data
	def give_class(self) : return self.the_class
	def give_data(self) : return self.the_data

class B :
	def give_class(self) : return str
	def give_data(self) : return 'hello world'

class C :
    def do_something(self,x) :
        print 'this is an object of class C'
        print 'the data is: ', x
        print 'and this is what i do with the data...'

class D :
    def do_something(self,x) :
        print 'this is an object of class D'
        print 'the data is: ', x
        print 'and i do something else...'

def a_function( obj ) :
        cls = obj.give_class()
        dat = obj.give_data()
        inst = cls()
        inst.do_something(dat)

def another_function( obj, x ) :
        cls = obj.give_class()
        a = cls(x)
        b = obj.give_data()
        print a, ' + ', b, ' == ', a+b 
        return a+b

def run() :
    a1 = A( C, ( 1, 'abcd', {} ) )
    a2 = A( D, [ i*3 + 1 for i in range(200,300) if i%17 == 0 ] )
    a3 = A( int, 56 )
    b = B()
    a_function( a1 )
    print '---------'
    a_function( a2 )
    print '---------'
    print another_function( a3, 1234 ), '\n---------'
    print another_function( b, 'I say: ' )

if __name__ == '__main__' :
    run()

Output:
>>> 
this is an object of class C
the data is:  (1, 'abcd', {})
and this is what i do with the data...
---------
this is an object of class D
the data is:  [613, 664, 715, 766, 817, 868]
and i do something else...
---------
1234  +  56  ==  1290
1290 
---------
I say:   +  hello world  ==  I say: hello world
I say: hello world
>>> 




Topic archived. No new replies allowed.