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

本文涉及的产品
访问控制,不限时长
简介: 【六、继承】多继承、继承中的构造函数和析构函数、类成员访问控制

一、类成员的访问控制

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类构造函数。

系列文章

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

【七、多态】


相关实践学习
消息队列+Serverless+Tablestore:实现高弹性的电商订单系统
基于消息队列以及函数计算,快速部署一个高弹性的商品订单系统,能够应对抢购场景下的高并发情况。
云安全基础课 - 访问控制概述
课程大纲 课程目标和内容介绍视频时长 访问控制概述视频时长 身份标识和认证技术视频时长 授权机制视频时长 访问控制的常见攻击视频时长
相关文章
|
5月前
|
Java 数据安全/隐私保护
Java基础手册二(类和对象 对象创建和使用 面向对象封装性 构造方法与参数传递 this关键字 static关键字 继承 多态 方法覆盖 final关键字 访问控制权限修饰符)
Java基础手册二(类和对象 对象创建和使用 面向对象封装性 构造方法与参数传递 this关键字 static关键字 继承 多态 方法覆盖 final关键字 访问控制权限修饰符)
34 0
|
数据安全/隐私保护 C++
43 C++ - 派生类访问控制
43 C++ - 派生类访问控制
57 0
|
6月前
|
数据安全/隐私保护 C++
C++ 类方法解析:内外定义、参数、访问控制与静态方法详解
C++ 中的类方法(成员函数)分为类内定义和类外定义,用于操作类数据。类内定义直接在类中声明和定义,而类外定义则先在类中声明,再外部定义。方法可以有参数,访问权限可通过 public、private 和 protected 控制。静态方法与类关联,不依赖对象实例,直接用类名调用。了解这些概念有助于面向对象编程。
125 0
|
6月前
|
存储 数据安全/隐私保护 C++
第十五章:C++访问控制权限、继承和多态详解
第十五章:C++访问控制权限、继承和多态详解
288 0
|
数据安全/隐私保护 C++
C++访问控制、派生类构造与析构函数
C++访问控制、派生类构造与析构函数
C++访问控制、派生类构造与析构函数
|
Java 数据安全/隐私保护 Android开发
Android C++系列:C++最佳实践3继承与访问控制
整个结构还是比较简单的,从类内部到本包到子类到外部包权限越来越小,比较好理解也比较好记忆。但是在C++中访问控制要复杂很多,因为不仅有属性和方法的访问控制,还有继承时的派生列表访问说明符。今天我们着重了解访问控制。
101 0
|
数据安全/隐私保护 C++
派生类的访问控制和类型兼容规则
派生类继承了基类的全部数据成员和除了构造、析构函数之外的全部函数成员,但是这些成员的访问属性在派生的过程中是可以调整的。从基类继承的成员,其访问属性由继承方式控制。 基类的成员可以有 public、protected 和 private 三种。基类的自身成员可以对基类中任何一个其他成员进行访问,但是通过基类的对象就只能访问该类的公有成员。
299 0
|
数据安全/隐私保护
访问控制与继承
每个类分别控制自己的成员初始化过程,与之类似,每个类还分别控制着成员对于派生类来说是否可访问。   受保护的成员 如前所述,一个类使用protected关键字来声明那些它希望与派生类分享但是不想被其他公共访问使用的成员。
570 0
|
3天前
|
安全 网络安全 数据安全/隐私保护
访问控制列表(ACL)是网络安全中的一种重要机制,用于定义和管理对网络资源的访问权限
访问控制列表(ACL)是网络安全中的一种重要机制,用于定义和管理对网络资源的访问权限。它通过设置一系列规则,控制谁可以访问特定资源、在什么条件下访问以及可以执行哪些操作。ACL 可以应用于路由器、防火墙等设备,分为标准、扩展、基于时间和基于用户等多种类型,广泛用于企业网络和互联网中,以增强安全性和精细管理。
27 7