Wednesday, December 30, 2015

Nested Classes in C++


A nested class/struct is a class which is declared in another enclosing class.As any other members of its enclosing class, nested class has access to all members to which the enclosing class has access,The members of an enclosing class have no special access to members of a nested class;

Note: Declarations in a nested class can use only type names, static members, and enumerators from the enclosing class.

Also, nesting a class within another class does not give the enclosing class special access privileges to member functions of the nested class.
A class can be nested in every part of the surrounding class: in the public, protected or private section. Such a nested class can be considered a member of the surrounding class. The normal access and rules in classes apply to nested classes. If a class is nested in the public section of a class, it is visible outside the surrounding class. If it is nested in the protected section it is visible in subclasses, derived from the surrounding class, if it is nested in the private section, it is only visible for the members of the surrounding class.

To refer to a nested class from outside of its enclosing class scope, you must use a fully qualified name.

Under what circumstance should be nested classes be used?

// 1. Nested class are cool for hiding implementation details
// 2. Nested class have additional access restriction
// 3. Nested class don't pollute the given namespace(e.g. global namespace)

// 1.
class List{
public:
    List(): head(nullptr), tail(nullptr){}
private:
    struct Node{
        Node(int data):_data(data){}
        int _data;
        Node *next, *prev;
    };
    Node *head;
    Node *tail;

};

// 2. Introducing another scope inside a class scope
class Product{
    public:
    enum ProductType{ FANCY, AWESOME, USEFUL };
    enum ProductBoxType{BOX, BAG, CRATE};
    Product(ProductType t, ProductBoxType b, std::string name);
};
// call
Product p(Product::FANCY, Product::BOX);
// When looking at code completion proposals for Product::, one will often get all
// the possilbe enum values(BOX, FANCY, CRATE) listed and it's easy to make a
// mistak here(c++11's strongly typed enum come to save)

// You can solve this by instroducing additional scope for those enums using
// nested classes, like this:
class Product{
public:
    struct ProductType{ enum Enum{FANCY, AWESOME, USEFUL} };
    struct ProductBoxType{ enum Enum{BOX, BAG, CRATE} };
    Product(ProductType::Enum t, ProductBoxType::Enum b, std::string name);
};
//call
Product p(Product::ProductType::FANCY, Product::ProductBoxType::BOX);

// 3.PIMPL idiom
// the PIMPL(short for Private Implementation) is an idiom to remove
// the implementation details of a class from the header.
// this reduces the need of recompiling classes depending on the class's
// header whenever the "implementation" part of the header changes

// a.h
class X{
public:
    X();
    virtual ~X();
    void Interface();
    void Interface2();
private:
    struct Impl;
    std::unique_ptr<Impl> impl;
};

// a.cpp
#include "a.h"
#include <windows.h>
struct X::Impl{
   HWND hWnd; // this field is a part of the class, no need to include windows.h
   // all privatge fields, methods go here
   void privateMethod(HWND wnd);
   void privateMethod();
};

X::X() : imple(new Imple()){
    //...
}


continue...
// An inner/nested class is a friend of the class(Outer/encloding) it is
// defined within.
// but unlike Java, there is no relation between an instance of inner class
// and an instance of the outer class
// This means: an object of type Outer does not contain any objects of
// type Inner

// Important: Nested classes declare only types within class scope.
// They do not cause contained objects of the nested class to be created.

// Visibility outside of the Outer class.
// Normally, the inner class is not visible from outside of the Outer class,
// for example:
class Outer{
public:
    class Inner1; // forward declaration, visible from outside of Outer
    class Inner2 {}; // definition, not visible from outside of Outer
};
int main(){
   Inner1 *in1; // ok
   Inner2 *in2; // error;
   Outer::Inner2 *in2; // ok
}

// Inner class has Outer class as a private member
class Outer{
public:
    Outer():i(*this), var(9){}
    Outer(Outer& other):i(other), var(15){}
    void func(){i.func();}
private:
    static const char* const MYCONST;
    Inner i;
    int var;
private:
    class Inner{
    public:
        Inner(Outer& x): _outer(x){}
        void func(){}
    };
    private:
        Outer& _outer;
};
int main(){
    Outer a1;
    Outer a2(a1);
    a1.func();
    a2.func();
}

// Since C++11, an inner class has access to all members of the outer class,
// but it does not have an implicit reference to a outer class instance.
// but if you pass a refernce of the outer class's instance to the inner class's

// instance, it can access anything(private or public) in the outer class instance



int x,y; // globals
class enclose { // enclosing class
    int x; // note: private members
    static int s;
 public:
    struct inner { // nested class
        void f(int i) {
            x = i; // Error: can't write to non-static enclose::x without instance
            int a = sizeof x; // Error until C++11,
                              // OK in C++11: operand of sizeof is unevaluated,
                              // this use of the non-static enclose::x is allowed.
            s = i;   // OK: can assign to the static enclose::s
            ::x = i; // OK: can assign to global x
            y = i;   // OK: can assign to global y
        }
        void g(enclose* p, int i) {
            p->x = i; // OK: assign to enclose::x
        }
    };
};
friend functions defined within a nested class has no special access to the members of the enclosing class even if lookup from the body of a name function that is defined within a nested class can find the private members of the enclosing class.
Out-of-class definitions of the members of a nested class appear in the namespace of the enclosing class:
struct enclose {
    struct inner {
        static int x;
        void f(int i);
    };
};
int enclose::inner::x = 1; // definition
void enclose::inner::f(int i) {} // definition
Nested classes can be forward-declared and later defined, either within the same enclosing class body, or outside of it:
class enclose {
    class nested1; // forward declaration
    class nested2; // forward declaration
    class nested1 {}; // definition of nested class
};
class enclose::nested2 { }; // definition of nested class



#include <iostream>
using namespace std;
class C1{
public:
    C1():mData(500){}
    void modifyB1(int var){
       mPb1->modifyme(var);
    }
    struct B1;// forward declaration
    void setB1(B1 *ptr){
        mPb1 = ptr;
    }
    struct B1{
        B1():mB1data(1111){}
        void bfoo(){ cout << mB1data << endl; } 
        void modifyme(int newdata){
            mB1data = newdata;
        }
        void print(){
            cout << "mB1data:" << mB1data << endl;
        }
    private:
        int mB1data;
    };
private:
    int mData;
    void foo(){}
    B1 *mPb1;
    //friend class B1;

};

#include "nest1.h"

int main(){
    C1 c1;
    C1::B1 b1;
    //b1.bfoo();
    c1.setB1(&b1);
    b1.print();
    c1.modifyB1(1080); 
    b1.print();
}

Program 1
#include <iostream>
class Enclosing {     
   int x;
   class Nested { // Nested class declaration 
      int y;  
      void NestedFun(Enclosing *ptr) {
        std::cout << ptr->x;  // OK: nested class can access
                              // private members of Enclosing class
      }      
   };
};
int main(){...}

Program 2
#include<iostream>
 class Enclosing {     
   int x;
   class Nested { // Nested class declaration
      int y;  
   }; 
   void EnclosingFun(Nested *n) {
        std::cout << n->y;  // Compiler Error: y is private in Nested
   }     
};
int main(){...}


Member classes of Template Class

// inst1.h
#include <iostream>

template<typename T>
class Base3{
public:
    template<typename U>
    struct S{
        void print(const char* a){
            std::cout << a << std::endl;
        }
    };
    template<typename U>
    void print(S<U> *ptr, const char *msg){
        ptr->print(msg);
    }
private:
    // Important:
    // member variable template can only be static
    // data member!
    // template<typename U>
    // S<U> *m_ptr;
};

template class Base3<int>::S<double>; // explicit instantiation

#include "inst1.h"
int main(){
    Base3<int> b3;
    Base3<int>::S<double> s;
    s.print("what's up!");
    b3.print<double>(&s, "I am good!");
}



http://www.oopweb.com/CPP/Documents/CPPAnnotations/Volume/cplusplus16.html

No comments:

Post a Comment