C++快速入门2——面向对象编程

1、继承的三种权限

  • public:类内类外都能访问。
  • protected:类内和子类可以访问,类外不能访问。
  • private:只允许类内访问,子类和类外都不能访问。

2、调整继承权限

使用using 类名::变量名或方法,可以控制单个成员或方法的继承权限。使用方法如下,Son继承了Father之后,将Father类里的key权限改为public,外界也可以访问了;如果放在Son类的private下,那么key就变为Son私有的了,不能再被Son的子类所继承。

class Father
{
	protected key;
};

class Son :public Father 
{
public:
	using Father::key;
}

3、继承类型

继承类型共有9种组合情况,原则就是最低权限原则,例如private + protected,那么继承后的权限就是private,取两者之间较小的那个。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IkbpsDgh-1611509116567)(C:\Users\85114\AppData\Roaming\Typora\typora-user-images\image-20210121222038995.png)]

4、多重继承

一个类可以同时从多个基类继承,如SofaBed同时继承Sofa和Bed。

class SofaBed : public Sofa, public Bed
{

}

5、虚拟继承

多重继承时,可能继承的多个基类里面有相同的成员或方法,此时就会出现二义性。虚拟继承可以很好的解决二义性问题,同时也解决了内存浪费问题(相同的成员或方法只保留一份)。虚拟继承会额外多出4字节的偏移量指针,可百度虚拟继承内存分布。

class SofaBed : virtual public Sofa, virtual public Bed
{

}

虚拟继承的构造函数和析构函数调用顺序:

  1. 首先执行虚基类的构造函数,多个虚基类的构造函数按照被继承的顺序构造;
  2. 执行基类的构造函数,多个基类的构造函数按照被继承的顺序构造;
  3. 执行成员对象的构造函数,多个成员对象的构造函数按照申明的顺序构造;
  4. 执行派生类自己的构造函数;
  5. 析构以与构造相反的顺序执行;

6、子类给基类构造函数传参

子类可以在构造函数中直接给基类构造函数传参,方式为基类(入参)、成员类名(入参),这些构造函数的调用顺序与书写的前后顺序无关,而是按照第5部分所述顺序进行调用。

class SofaBed : virtual public Sofa, virtual public Bed
{
private:
	Data data;	/* Data类 */
public:
   	/* SofaBed构造函数 */
    SofaBed(char *str1, char*str2, char *str3, char* str4) : Sofa(str1), Bed(str2), data(str3)
    {
        
    }
}

7、多态的实现

多态需要依靠虚函数来实现。

#include <iostream>
using namespace std;

class Human {
private:
    int a;
public:
	virtual void eat(void) {cout<<"use hand to eat"<<endl;}
};

class English:public Human{
public:
	void eat(void){cout<<"use knife to eat"<<endl;}
};

class Chinese:public Human{
public:
	void eat(void){cout<<"use chopsticks to eat"<<endl;}
};

void eatTest(Human &human)
{
	human.eat();
}

int main(int argc, char **argv)
{
	Human h;
	English e;
	Chinese c;
	
	eatTest(h);
	eatTest(e);
	eatTest(c);
}

执行结果如下:

use hand to eat
use knife to eat
use chopsticks to eat

如果去掉Human类中eat方法的virtual属性,或者将void eatTest(Human &human)函数改成void eatTest(Human human),调用结果如下,这样就无法实现多态了。只有通过指针或者引用才能实现多态,直接传值是不行的。

use hand to eat
use hand to eat
use hand to eat

8、多态的原理

程序分为静态联编和动态联编。对于静态联编,在编译时就已经确定好了会调用的函数,非虚函数的情形正是静态联编的;对于动态联编,会在程序运行时动态地确定调用的函数,如虚函数的情况。静态联编效率高,动态联编支持多态。

对于类中有虚函数的情况,该类中会有指针指向一个虚函数表,在调用时会通过指针找到虚函数表中的对应函数并调用,如下图所示。

在这里插入图片描述

对于上面的例子,sizeof(h)= sizeof(e) = sizeof(c) = 16。因为虚函数表里面不仅包含了虚函数指针,还包含了类的一些以及继承信息

9、多态的限制

  • 只有类的成员才能声明为虚函数。
  • 静态成员函数不能是虚函数。
  • 内联函数不能是虚函数。
  • 构造函数不能是虚函数。
  • 析构函数一般都声明为虚函数。如果析构函数不声明为虚函数,那么子类在析构时,只会调用父类的析构函数,不会调用本类的析构函数。
  • 重载的函数不能是虚函数。
  • 当函数参数相同,且返回值为该类的指针或引用时,允许声明为虚函数;如果返回值为其他类型,则不允许设置为虚函数。

猜你喜欢

转载自blog.csdn.net/qq_27575841/article/details/113101405