继承的类的前面加上virtual关键字表示被继承的类是一个虚基类,它的被继承成员在派生类中只保留一个实例
声明指向类的指针时,不管引用的实例是哪个类的, 当你调用的时候系统会调用左值那个对象所属类的方法
用C++开发的时候,用来做基类的类的析构函数一般都是虚函数
这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。
并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。
所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。
[code]
class ClxBase
{
public:
ClxBase() {};
virtual ~ClxBase() {};
virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
};
class ClxDerived : public ClxBase
{
public:
ClxDerived() {};
~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };
void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
};
ClxBase *pTest = new ClxDerived;
pTest->DoSomething();
delete pTest;
[/code]
class A
{
public:
int iValue;
};
class B:public A
{
public:
void bPrintf(){cout<<"This is class B"<<endl;};
};
class C:public A
{
public:
void cPrintf(){cout<<"This is class C"<<endl;};
};
class D:public B,public C
{
public:
void dPrintf(){cout<<"This is class D"<<endl;};
};
void main()
{
D d;
cout<<d.iValue<<endl; //错误,不明确的访问
cout<<d.A::iValue<<endl; //正确
cout<<d.B::iValue<<endl; //正确
cout<<d.C::iValue<<endl; //正确
}
从代码中可以看出类B C都继承了类A的iValue成员,因此类B C都有一个成员变量iValue ,而类D又继承了B C,这样类D就有一个重名的成员 iValue(一个是从类B中继承过来的,一个是从类C中继承过来的).在主函数中调用d.iValue 因为类D有一个重名的成员iValue编译器不知道调用 从谁继承过来的iValue所以就产生的二义性的问题.正确的做法应该是加上作用域限定符 d.B::iValue 表示调用从B类继承过来的iValue。不过 类D的实例中就有多个iValue的实例,就会占用内存空间。所以C++中就引用了虚基类的概念,来解决这个问题。
class A
{
public:
int iValue;
};
class B:virtual public A
{
public:
void bPrintf(){cout<<"This is class B"<<endl;};
};
class C:virtual public A
{
public:
void cPrintf(){cout<<"This is class C"<<endl;};
};
class D:public B,public C
{
public:
void dPrintf(){cout<<"This is class D"<<endl;};
};
void main()
{
D d;
cout<<d.iValue<<endl; //正确
}
在继承的类的前面加上virtual关键字表示被继承的类是一个虚基类,它的被继承成员在派生类中只保留一个实例。例如iValue这个成员,从类 D这个角度上来看,它是从类B与类C继承过来的,而类B C又是从类A继承过来的,但它们只保留一个副本。因此在主函数中调用d.iValue时就不 会产生错误。
声明指向类的指针时,不管引用的实例是哪个类的, 当你调用的时候系统会调用左值那个对象所属类的方法
class A
{
public:
void funPrint(){cout<<"funPrint of class A"<<endl;};
};
class B:public A
{
public:
void funPrint(){cout<<"funPrint of class B"<<endl;};
};
void main()
{
A *p; //定义基类的指针
A a;
B b;
p=&a;
p->funPrint();
p=&b;
p->funPrint();
}
答案是funPrint of class A 与 funPrint of class A
因为p是一个A类的指针,所以不管你将p指针指向类A或是类B,最终调用的函数都是类A的funPrint 函数。这就是静态联篇,编译器在编译的时候就已经确定好了
如果我想实现跟据实例的不同来动态决定调用哪个函数呢?这就须要用到 虚函数(也就是动态联篇)
在基类的成员函数前加virtual关键字表示这个函数是一个虚函数,所谓虚函数就是在编译的时候不确定要调用哪个函数,而是动态决定将要调 用哪个函数,要实现虚函数必须派生类的函数名与基类相同,参数名参数类型等也要与基类相同。但派生类中的virtual关键字可以省略,也表 示这是一个虚函数
class A
{
public:
virtual void funPrint(){cout<<"funPrint of class A"<<endl;};
};
class B:public A
{
public:
virtual void funPrint(){cout<<"funPrint of class B"<<endl;};
};
void main()
{
A *p; //定义基类的指针
A a;
B b;
p=&a;
p->funPrint();
p=&b;
p->funPrint();
}
funPrint of class A
funPrint of class B
用C++开发的时候,用来做基类的类的析构函数一般都是虚函数
这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。
并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。
所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。
[code]
class ClxBase
{
public:
ClxBase() {};
virtual ~ClxBase() {};
virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
};
class ClxDerived : public ClxBase
{
public:
ClxDerived() {};
~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };
void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
};
ClxBase *pTest = new ClxDerived;
pTest->DoSomething();
delete pTest;
[/code]