类的constructor和继承 :
子类不能继承父类的constructor,只能调用父类的constructor,如果子类没有声明constructor,当构造子类的实例时,将执行其默认构造函数,该默认构造函数将会首先调用父类的默认构造函数,若父类没有默认构造函数,那么只好匹配默认参数的constructor。
子类可以直接访问父类的保护数据成员,但是这种方法并不好,最好通过父类的接口(member functions)来对其进行访问。原因是一但父类出现了问题,只用修改父类。
在构造一个子类的实例时,完成其父类部分的构造由父类的constructor完成,而且总是从父类的构造开始的。
virtual和polymorphism :
当子类重载了父类的成员函数是:
class A
{
public:
void fun(){ }
};
class B : public A
{
public:
void fun(){ }
};
void main ()
{
A a;
B b;
a.fun();
b.fun();
}
各自调用自己的fun();只有当B没有定义自己的fun()时b的fun()才为A中定义的版本。但是如果:
class A
{
public:
void fun(){ }
};
class B : public A
{
public:
void fun(){ }
};
void Get(A & x)
{
x.fun();
}
void main()
{
A a;
B b;
Get(a);
Get(b);
}
因为B为A的子类,所以Get(A&)可以接受以上两种参数,Get(a)应该调用A的fun(),Get(b)应该调用B的fun(),但是生成exe后,函数调用的fun就会随实际的参数变化而变化,故会发生紊乱。因而引入polymorphism。能依据类型确定调用那个函数的能力叫polymorphism,或者late binding,反之为early binding。
用virtual关键字赋予member function具有polymorphism,在默认情况下编译器是early binding;只有看到virtual时才进行late binding,父类声明polymorphism后,会带给子类(省略)。
若父类和子类的函数返回类型函数名参数类型有一样不一样,即使声明virtual也无济于事,编译器照样进行late binding(因为polymorphism的本质就是同一个函数的多种行为,已经不是同一个函数谈何多态?)。但有种例外:父类的函数返回父类的指针或引用,子类返回子类的指针或引用,但其他必须一样,可以进行late binding。
应该尽量将类的成员函数声明为virtual函数,有好无坏。virtual函数针对类的member functions而言的。static && inline && constructor不能为virtual。destructor最好为virtual,原因是为了防止内存泄露。
没事写了些代码做实验:
父类声明virtual其他和子类一样:通过对象和全局函数一样:父类实例调父类的函数,子类的调子类的,与调用顺序无关。
将父类的virtual移到子类对应的函数前:通过对象调用:各自调用各自的,与调用顺序无关。
通过全局函数调用:两个都调用父类的,与调用顺序无关。
父类子类都不加virtual:通过对象调用:各自调各自的,与调用顺序无关
通过全局函数调用:两个都调用父类的
都加virtual就不用试了。
关于抽象类:
抽象类不能进行实例化,其主要作用是被继承,抽象类至少有一个纯虚函数(pure virtual function),纯虚函数在子类里未被重载前仍然是纯虚函数,故子类也仍然是抽象类。抽象类不能实例,但是可以声明其指针或引用