组合和继承的主要目的是为了代码的重用。组合是将其他类的对象作为成员使用,继承是子类可以使用父类的成员方法。
1、构造函数的调用次序:父类的构造函数——>成员对象的构造函数——>子类的构造函数;析构函数调用次序相反。
2、名字隐藏:在子类中重新定义类的一个函数,基类中的所有同名的函数被隐藏,重新定义则是指修改父类的函数的操作或者返回值类型。
如:  class A

{  
   int i;
   Class m;  
public:
   void f():i(0){}
   void f(int i){}//此时称为f函数重载,只能是参数值区别
   int g(){}
}
class B: public  A
{
  int f(){}//void f(String str),可以是修改参数类型或者返回值类型
  //此时可以称为f的多态,即子类可以对父类中的函数有多种不同的实现
}

此时,在类B中,将类A的f函数全部屏蔽。
3、子类继承父类,不显式声明为“Public”,则父类的方法自动继续为private的,如果上例声明为Class B:A{}时,则
                Class B obj;
                obj.g();//非法,此时g()在类B中是默认私有的
如果是class B:public A{},此时就可以通过B的对象访问g()方法了。
3、子类可以继承子类的成员方法,但是不能继承构造函数、析构函数以及赋值运算符operator=。如果用户没有显式定义,则编译器自动为类生成。

class B{
public :
   B(){cout << "B()"<<endl;}
//B(int i){},非默认构造函数
};
class A {
int i;
B b;
public:
   A() :i(0){ cout << "A()\n"<<endl; }
   A( const A & ) { cout << "A(constA&)\n";  }
};
int main() {  A a;}

上例中,声明A时自动调用B的默认构造函数B(),如果没有默认的构造函数则会报错

class B{
public :
   //B(){cout << "B()"<<endl;}
B(int i){},非默认构造函数
};
class A {
int i;
B b;
public:
   A() :i(0){ cout << "A()\n"<<endl; }
   A( const A & ) { cout << "A(constA&)\n";  }
};
int main() {  A a;A b=a;} 会报错,因为调用A的拷贝构造函数时,成员b的初始化没有办法执行。改成A( const A & ) :b(i)则没有错误了。

【注】使用拷贝构造函数时,必须显式的声明成员变量和对象的初始化,对于变量i使用i(ii),对于对象b,因为没有默认的构造函数,必须显示的调用B(int);
    如果类A的拷贝构造函数不显式初始化成员对象b,编译器会调用成员对象b的默认构造函数,如果成员对象的类B没有默认的构造函数,则会报错,此时必须显式的调用用户定义的构造函数B(int)
     如果B中没有任何构造函数,如    

class B{ };
class A {
int i;
B b;
public:
   A() :i(0){ cout << "A()\n"<<endl; }
   A( const A & ) { cout << "A(constA&)\n";  }
};
int main() {  A a;A a1=a;}//此时编译器会为b调用什么构造函数呢?猜是拷贝构造函数

4、对于组合和继承的选择,如果不需要进行向上类型转换则使用组合,否则使用继承