关于继承和多态之前的博客中有讲到,但因为最近在复习C++的一些概念,所以把一些遗漏的同样是重点的知识点再简单整理一下,具体基础知识请戳链接:
继承:http://blog.csdn.net/chaseraod/article/details/69704143
多态:http://blog.csdn.net/chaseraod/article/details/69704143
1,C++的三大特性是什么?分别说说你的理解。
封装、继承、多态。
(1)封装:封装是C++面向对象的一大特性。是指隐藏对象的具体属性和实现方式,只对外界暴露公共接口。封装的好处:.将变化隔离;2.便于使用。4.提高安全性。
(2)继承:父类原有的特性在加上某种限制(public、protected、private)后,子类同样具有其特性,并且可以加上自己独有的特性,继承实现了复用性,在现实中的应用广泛。
(3)多态:多态是通过virtual关键字实现虚函数的重写,以及父类指针或引用实现动态绑定。
2,如何让一个类不能被继承?
这道题考查队继承的理解,子类的初始化一定会去调用父类的构造函数,因此当我们把父类的构造函数设为私有时,这个类就不能被继承。
代码:
class AA
{
private:
AA()
{}
protected:
int _a;
}
class BB:public AA
{
public:
BB()
{}
private:
int _b;
3,什么情况下必须把父类的析构函数设为私有,如果不设为私有,会有什么危害?
我们先来看以下代码:
class A
{
public:
~A()
{
cout << "~A()" << endl;
}
};
class B :public A
{
public:
~B()
{
cout << "~B()" << endl;
}
};
int main()
{
A *p = new B;
delete p;
system("pause");
return 0;
}
运行结果:
可以看到,程序运行后并没有调用子类的析构函数,如果在子类的析构函数中有其他的工作,那么造成的损失将会很大。这里了是因为析构函数不够成多态,所以在动态联编时只会调用父类的析构函数。所以,通常我们将父类的析构函数设为虚函数,这样防止内存泄漏的损失。
4,C++类的成员函数中重载、重写(覆盖)、重定义(隐藏)分别是什么?
重载:(1)在同一作用域
(2)函数名相同、参数不同
(3)返回值可以不同
重写:(1)不在同一作用域(分别在基类和派生类)
(2)函数名相同、参数相同、返回值相同(协变除外)
(3)基类函数必须有virtual关键字
(4)访问修饰符可以不同
重定义:(1)在不同作用域中
(2)函数名相同
(3)在基类和派生类中只要不构成重写就是重定义
5,虚继承和多态中虚函数的区别
(1)虚继承
相信很多初学者都会分不清虚继承中的virtual和多态中的virtual,很多情况下会将他们搞混,但是它们之间并没有一点联系。
我们来看下面的代码:
class A
{
public:
int _a;
};
class B :public A
{
public:
int _b;
};
class C :public A
{
public:
int _c;
};
class D :public B, public C
{
public:
int _d;
};
int main()
{
D d;
d._a = 1;
d._b = 2;
d._c = 3;
d._d = 4;
system("pause\n");
return 0;
}
上面的程序就是菱形继承:
程序一运行,会报这样的错
A类和B类中都有_a,就是菱形继承产生的二义性问题。虚继承就是解决菱形继承的二义性和数据冗余问题的。
class A
{
public:
int _a;
};
class B :virtual public A
{
public:
int _b;
};
class C :virtual public A
{
public:
int _c;
};
class D :public B, public C
{
public:
int _d;
};
int main()
{
D d;
d._a = 1;
d._b = 2;
d._c = 3;
d._d = 4;
system("pause\n");
return 0;
}
此时编译通过,程序中_a只有一份。
那么,类A、B、C、D的大小各是多少呢?
为什么B和C的大小会是12字节呢?
通过上述的调试过程我们也可以看到,B中有成员_a,_b . C中有成员_a,_c,本应该是8字节,却多出了四个字节。
因为它们都是虚继承,内存中实际上有一个虚基表用来保存每个成员的相对偏移量,虚基类成员必须放在对象的最底层。所以,多出的四个字节实际是指向这个虚基表的指针。
(2)多态中的虚函数
class AA
{
public:
AA()
{}
virtual ~AA()
{}
virtual void Print()
{
cout << "I am AA" << endl;
}
private:
int _a;
};
class BB:public AA
{
public:
BB()
{}
~BB()
{}
void Print()
{
cout << "I am BB" << endl;
}
private:
int _b;
};
int main()
{
AA *p = new AA;
AA *p1 = new BB;
p->Print();
p1->Print();
system("pause");
return 0;
}
运行结果:
这里的virtual是为了实现动态联编以实现多态。那么,类A,B的大小又是多少呢?
这里多出的四个字节和上面的一样吗?不一样!!!
多态中有一个虚表,但这里的虚表不同于虚继承中的虚基表,这里的虚表指的是虚函数表,一个类中有虚函数,则这个类的所有对象都含有一个指向虚表的指针,且所有的虚表指针指向同一个虚表,因此多出的四个字节便是这虚表指针的大小。