【六、继承】多继承、继承中的构造函数和析构函数、类成员访问控制

简介: 【六、继承】多继承、继承中的构造函数和析构函数、类成员访问控制

一、类成员的访问控制

C++类成员的访问控制主要有三种权限,分别是:

public:可在类内部使用、可在派生类内部使用、可在类外部使用;

protected:可在类内部使用、可在派生类内部使用、不可在类外部使用;

private:可在类内部使用、不可在派生类内部使用、不可在类外部使用;

在类中不写权限默认为private私有属性,而struct默认为public公有属性。这里有一个小坑需要注意,有时候我们在写构造函数的时候如果忘记加public,那么该构造函数默认为private私有,这将导致我们在定义对象的时候出错

#include <iostream>
using namespace std;
class A
{
  A(int a, int b)
  {
    this->a = a;
    this->b = b;
  }
private:
  int a;
  int b;
};
int main()
{
  A a1(1, 2);
  system("pause");
  return 0;
}

编译程序会报错

因为构造函数默认为private,在外部不可访问,所以报错。只要在构造函数加上public权限即可。

二、继承

继承是C++的三大特性之一,通过继承可以实现代码复用。被继承的类称为基类,继承的类称为派生类,派生类是一种特殊的基类,它继承了基类除构造函数和析构函数之外的全部属性和方法,并且可以拥有自己的属性和方法,在继承过程中,派生类可以通过继承的属性来调整从基类继承的父类成员的对外访问属性。

public继承:父类public属性的成员在子类依然是public、父类protecte属性成员在子类依然是protected、父类private属性在子类依然是private ;(不改变父类中的属性)

protected继承:父类public属性的成员在子类变为protected、父类protected属性成员在子类依然是protected、父类private属性在子类依然是private;

private继承:父类public属性的成员在子类变为private、父类protected属性成员在子类变为private、父类private属性在子类依然是private;(全部变为private属性)

使用派生定义对象时,基类的私有成员其实也存在于派生类定义的对象中的,只不过无法访问。

继承案例

#include <iostream>
using namespace std;
class A
{
public:
  int a;
  void print_data_a()
  {
    cout << a << " " << b << " " << c << endl;
    cout << "A 类成员函数" << endl;
  }
protected:
  int b;
private:
  int c; //private 只能在自己内部使用 --- 私人使用
public:
  A(int a, int b, int c)
  {
    this->a = a;
    this->b = b;
    this->c = c;
    cout << "A 类构造函数" << endl;
  }
  ~A()
  {
    a = b = c;
    cout << "A 类析构函数" << endl;
  }
};
//public 用于需要对外访问的情况(在类的外部访问)--- 公用
class B : public A
{
public:
  void print_data_b()
  {
    cout << a << endl;
    cout << b << endl;
    //cout << c << endl; //A 的私有属性,不可访问
    cout << "B 类成员函数" << endl;
  }
protected:
private:
public:
  B(int a, int b, int c) : A(a, b, c) //转去调用 A 类构造函数
  {
    cout << "B 类构造函数" << endl;
  }
  ~B()
  {
    cout << "B 类析构函数" << endl;
  }
};
//protected 用于在类及它的派生类中访问的情况(只能在派生类内部使用)--- 家族使用
class C : protected A
{
public:
  void print_data_c()
  {
    cout << a << endl;
    cout << b << endl;
    //cout << c << endl; //A 的私有属性,不可访问
    cout << "C 类成员函数" << endl;
  }
protected:
private:
public:
  C(int a, int b, int c) : A(a, b, c)
  {
    cout << "C 类构造函数" << endl;
  }
  ~C()
  {
    cout << "C 类析构函数" << endl;
  }
};
void func1()
{
  B b1(1, 2, 3); //先调用 A 构造函数, 再调用 B 构造函数
  b1.a = 10;
  b1.print_data_a();
  b1.print_data_b();
} //先调用 B 析构函数,再调用 A 析构函数
void func2()
{
  C c1(1, 2, 3);
  //c1.a = 10; //a 经过 protected 继承后变为 protected 属性
  //c1.print_data_a(); //print_data_a 经过 protected 继承后变为 protected 属性
  c1.print_data_c();
}
int main()
{
  func1();
  func2();
  system("pause");
  return 0;
}

三、继承中的构造与析构函数调用顺序

创建子类对象的时候,在执行子类构造函数的初始化列表时,会先调用父类构造函数,然后调用子类构造函数;析构子类对象时,会先调用子类析构函数释放子类资源,再调用父类析构函数释放从父类继承的资源。

#include <iostream>
using namespace std;
class MyClassA
{
public:
  MyClassA()
  {
    cout << "A 构造函数" << endl;
  }
  ~MyClassA()
  {
    cout << "A 析构函数" << endl;
  }
protected:
private:
};
class MyClassB
{
public:
  MyClassB()
  {
    cout << "B 构造函数" << endl;
  }
  ~MyClassB()
  {
    cout << "B 析构函数" << endl;
  }
protected:
private:
};
class MyClassC : public MyClassB
{
public:
  MyClassC() : MyClassB(), a1()
  {
    cout << "C 构造函数" << endl;
  }
  ~MyClassC()
  {
    cout << "C 析构函数" << endl;
  }
public:
  MyClassA a1;
protected:
private:
};
void FuncTest()
{
  MyClassC c1;
}
int main()
{
  FuncTest();
  system("pause");
  return 0;
}

编译运行,可以看到结果

先调用父类构造函数,在调用成员对象类的构造函数,最后调用自己的构造函数;析构函数调用顺序相反。

四、多继承

继承中如果子类和父类有同名变量,那么子类对象中,两个变量同时存在,用域作用符区分,默认情况下使用子类的成员,加父类的域作用符则使用父类的成员。继承中的静态成员要加域作用符。

#include <iostream>
using namespace std;
class MyClassB
{
public:
  int a;
  static int b;
  void B_printA()
  {
    cout << a << endl;
  }
protected:
private:
};
int MyClassB::b = 1; 
class MyClassC : public MyClassB
{
public:
  int a;
  void C_printA()
  {
    cout << a << endl;
  }
public:
protected:
private:
};
int main()
{
  MyClassC c1;
  c1.a = 1; //不加域作用符,默认使用子类
  c1.C_printA();
  c1.MyClassB::a = 2; //通过域作用符修改父类
  c1.C_printA();
  c1.B_printA();
  c1.b = 3; //如果要使用静态成员b,必须要有int MyClassB::b = 1; 这句话
        //如果不使用b,可以没有,编译运行都不报错
  system("pause");
  return 0;
}

五、多继承的二义性与虚继承

当C继承了B1和B2,而B1和B2都继承了A时,C定义的对象使用A成员时,就会出现二义性,因为编译器无法判断这个成员是B1继承的还是B2继承的。解决这种二义性的方法,一个是加与作用符,二是使用虚继承。

#include <iostream>
using namespace std;
class MyClassA
{
public:
  MyClassA()
  {
    cout << "A 构造函数" << endl;
  } 
  int a;
protected:
private:
};
//解决二义性:2.使用虚继承,虚继承只调用一次构造函数
//class MyClassB1 : virtual public MyClassA
class MyClassB1 : public MyClassA
{
public:
  int b1;
protected:
private:
};
//class MyClassB2 : virtual public MyClassA
class MyClassB2 : public MyClassA
{
public:
  int b2;
protected:
private:
};
class MyClassC : public MyClassB1, public MyClassB2
{
public:
  int c;
public:
protected:
private:
};
int main()
{
  MyClassC c1;
  //c1.a = 1; //错误(活动)  E0266 "MyClassC::a" 不明确 
  c1.MyClassB2::a = 1; //解决二义性:1.加域作用符
  system("pause");
  return 0;
}

编译程序运行可以看到:

普通继承调用两次A类构造函数;

虚继承只调用一次A类构造函数。

系列文章

【五、运算符重载实例分析】

【七、多态】


相关实践学习
云安全基础课 - 访问控制概述
课程大纲 课程目标和内容介绍视频时长 访问控制概述视频时长 身份标识和认证技术视频时长 授权机制视频时长 访问控制的常见攻击视频时长
相关文章
|
3天前
|
存储 数据安全/隐私保护 C++
第十五章:C++访问控制权限、继承和多态详解
第十五章:C++访问控制权限、继承和多态详解
206 0
|
Java 数据安全/隐私保护 Android开发
Android C++系列:C++最佳实践3继承与访问控制
整个结构还是比较简单的,从类内部到本包到子类到外部包权限越来越小,比较好理解也比较好记忆。但是在C++中访问控制要复杂很多,因为不仅有属性和方法的访问控制,还有继承时的派生列表访问说明符。今天我们着重了解访问控制。
72 0
|
数据安全/隐私保护
访问控制与继承
每个类分别控制自己的成员初始化过程,与之类似,每个类还分别控制着成员对于派生类来说是否可访问。   受保护的成员 如前所述,一个类使用protected关键字来声明那些它希望与派生类分享但是不想被其他公共访问使用的成员。
553 0
|
关系型数据库 Shell Linux
ACL(访问控制列表)权限管理
一、ACL权限 二、rwx权限 三、mask权限 四、ACL备份和恢复
|
3天前
|
安全 网络安全 数据安全/隐私保护
【专栏】IT 知识百科:访问控制列表(ACL)是网络安全的关键机制,用于定义和管理网络资源的访问权限
【4月更文挑战第28天】访问控制列表(ACL)是网络安全的关键机制,用于定义和管理网络资源的访问权限。ACL工作原理包括定义规则、匹配规则和执行操作。标准ACL基于源IP过滤,扩展ACL则提供更多筛选条件。时间及用户基础的ACL提供更细化的控制。优点在于增强安全性和精细管理,但管理复杂性和性能影响也是挑战。未来,ACL将趋向智能化和自动化,与更多安全技术结合,以提升网络安全。**
|
3天前
|
网络虚拟化 数据安全/隐私保护 数据中心
【专栏】对比了思科与华为网络设备的基本配置、接口、VLAN、路由、访问控制列表及其它关键命令
【4月更文挑战第28天】本文对比了思科与华为网络设备的基本配置、接口、VLAN、路由、访问控制列表及其它关键命令。尽管两者在很多操作上相似,如设备命名(思科:`hostname`,华为:`sysname`)、查看版本信息(思科:`show version`,华为:`display version`),但在某些方面存在差异,如接口速率设置(两者都使用`speed`和`duplex`,但命令结构略有不同)和VLAN配置(华为的`port hybrid`命令)。
|
3天前
|
网络协议 网络安全 网络性能优化
网络技术基础(14)——ACL访问控制列表
【3月更文挑战第3天】刚加完班又去南京出差了,实在是太忙了。。。。
|
9月前
|
网络安全 数据安全/隐私保护
访问控制列表与SSH结合使用,为网络设备保驾护航,提高安全性
访问控制列表与SSH结合使用,为网络设备保驾护航,提高安全性
97 0
访问控制列表与SSH结合使用,为网络设备保驾护航,提高安全性
|
安全 网络虚拟化 数据安全/隐私保护
华为ensp模拟器 配置ACL访问控制列表
华为ensp模拟器,模拟配置acl访问规则,配置acl访问规则的详细解释和操作。
华为ensp模拟器 配置ACL访问控制列表
|
11月前
|
安全 网络协议 网络安全
访问控制列表(ACL)
访问控制列表(ACL)
200 0