首页 > 编程语言 >C++基础杂记(3)

C++基础杂记(3)

时间:2023-10-31 13:34:36浏览次数:30  
标签:基类 Basic 函数 val 派生类 基础 C++ 杂记 basic



类的继承

基类与派生类之间的构造行为

派生类可以调用基类的公共成员,但无法调用基类的私有成员。所以派生类无法直接初始化基类中的私有成员变量。在派生类中初始化基类的私有成员变量需要显式的调用基类的构造函数,并以委托构造的方式将其初始化。

// 基类头文件 basic.h
#ifndef __BASIC__
#define __BASIC__

class Basic
{
private:
    int basic_pri_val;
    void basicPriFuc() const;
public:
    Basic(int _pri_val, int _pub_val):basic_pri_val(_pri_val), basic_pub_val(_pub_val){}
    int basic_pub_val;
    void basicPubFuc() const;
    void showBasicPriVal() const;
};
#endif
// 基类源文件 basic.cpp
#include <iostream>
#include "basic.h"
using std::cout;
void Basic::basicPriFuc() const
{
    cout<< "Basic private function.\n";
}

void Basic::basicPubFuc() const
{
    cout<< "Baisc public function.\n";
}

void Basic::showBasicPriVal() const
{
    cout<< "Basic private value: "<< basic_pri_val<< '\n';
}
// 派生类头文件 derive.h
#ifndef __DERIVE__
#define __DERIVE__

#include "basic.h"

class Derive:public Basic   // 从 Basic 类派生
{
public:
    Derive(int _basic_pri_val, int _basic_pub_val):Basic(_basic_pri_val, _basic_pub_val){}  // 委托基类构造函数初始化基类成员变量
};

#endif
// 派生类源文件 derive.cpp
#include "derive.h"
// 主程序源文件 main.cpp
#include "derive.h"

int main()
{
    Derive derive = {1, 2};

    // derive.basicPriFuc();    // 不可访问基类私有成员函数
    derive.basicPubFuc();       // 可以访问基类公共成员函数
    // derive.basic_pri_val;    // 不可访问基类私有成员变量
    derive.showBasicPriVal();   // 基类私有成员变量可以通过基类公共成员函数访问
    derive.basic_pub_val;       // 可以访问基类公共成员变量

    return 0;
}

Baisc public function.
Basic private value: 1

另外,基类的引用或指针可以指向派生类,但这样的引用和指针只能调用来自于基类的方法。

在派生类中使用基类方法

在派生类中使用基类方法只需要在方法前加上域解析运算符,如下:

// 假定类 Basic 中已经定义了 myPrint 方法
class Derive:: public Basic
{
public:
    void myPrint()
    {
        Basic::myPrint();   // 调用类 Basic 中的 myPrint 方法
        myPrint();          // 调用类 Derive 中的 myPrint 方法
    }
}

protected 的访问权限

对于类外而言,protected 的访问权限与 private 相似。对于派生类而言, protected 的访问权限与 public 相似。

多态公有继承

在进行本节之前需要知道:父类的指针/引用可以指向/引用派生类,但只能调用继承于父类的方法或重写在子类中的虚方法。

多态有静态多态和动态多态两个部分。

  • 静态多态相当于在派生类中重写了(不是重载)父类中的函数,函数的声明中,形参类型和数量可以与父类不一致。派生类只能调用重写后的函数,而不能够再使用被重写的父类中的函数。
  • 动态多态发生在使用父类指针或引用,调用或重写修函数时。下面将进行详细的演示。

关键字 virtual

  • 只有类的非静态成员函数可以成为虚函数,其他非类成员函数或类的静态成员函数不行。
  • 类中的虚函数,即使不被调用也必须被定义。而非虚函数在不被调用的情况下可以只声明不定义。
  • 派生类与父类中的虚函数声明必须完全一致,包括函数名与形参类型。
  • virtual 还可用于类的虚继承。

使用 virtual 修饰类的成员函数,其成员函数的调用行为只在下列情况下不同:

  • 对于一般的成员函数,如果使用类的指针或者引用来调用该函数,则函数的行为将取决于声明该指针/引用的类型。即如果是父类类型的的指针/引用,则将调用父类中的函数;如果是派生类类型的指针/引用,则将调用派生类中的函数。
  • 对于虚成员函数,如果使用类的指针或引用来调用该函数,则函数的行为取决于指针所指向的对象的类型。

示例

// 基类头文件 basic.h
#ifndef __BASIC__
#define __BASIC__

class Basic
{
private:
    int basic_pri_val;
    void basicPriFuc() const;
public:
    Basic(int _pri_val, int _pub_val):basic_pri_val(_pri_val), basic_pub_val(_pub_val){}
    // virtual ~Basic() {}; // 在包含虚函数时,应当包含一个虚析构函数
    int basic_pub_val;
    void basicPubFuc() const;
    void showBasicPriVal() const;

    void myPrint() const;   // 非虚函数,下面将在派生类中重写
};
#endif
// 基类源文件 basic.cpp
#include <iostream>
#include "basic.h"
using std::cout;
void Basic::basicPriFuc() const
{
    cout<< "Basic private function.\n";
}

void Basic::basicPubFuc() const
{
    cout<< "Baisc public function.\n";
}

void Basic::showBasicPriVal() const
{
    cout<< "Basic private value: "<< basic_pri_val<< '\n';
}

void Basic::myPrint() const
{
    cout<< "Basic class print.\n";
}
// 派生类头文件 derive.h
#ifndef __DERIVE__
#define __DERIVE__

#include "basic.h"

class Derive:public Basic   // 从 Basic 类派生
{
public:
    Derive(int _basic_pri_val, int _basic_pub_val):Basic(_basic_pri_val, _basic_pub_val){}   // 委托基类构造函数初始化基类成员变量

    void myPrint();     // 重写父类中的非虚函数

};

#endif
// 派生类源文件 derive.cpp
#include "derive.h"
using std::cout;
void Derive::myPrint() const
{
    cout<< "Derive class print.\n";
}
// 主程序源文件 main.cpp
#include "derive.h"

int main()
{
    Derive derive = {1, 2};
    Basic & basic = derive;
    basic.myPrint();

    return 0;
}

Basic class print.

当重写父类中的普通函数时,即使父类引用引用了派生类,但是该引用调用的却是父类中的函数。myPrint 函数的行为却决于引用类型。

如果我们在声明中为 myPrint() 函数加上 virtual 修饰,则程序结果为:

Derive class print

可以看到,myPrint() 函数的行为取决于引用所指向的类。

如果需要在派生类中重定义基类中的方法,则应尽量将该方法声明为虚。且需要在基类中声明一个虚析构函数。

当类被用作基类时,它的虚构函数应当被设置为虚函数,否则将会对派生类对象的内存释放造成麻烦。

抽象基类(ABC)

类中包含纯虚函数的类被称为抽象基类。纯虚函数的声明如下:

class ABC
{
public:
    virtual void myPrint() const = 0;
}

纯虚函数可以在抽象基类中被定义。抽象基类的派生类必须使用重写虚函数的方法来重写纯虚函数。抽象基类强制派生类实现其纯虚函数。

私有继承和保护继承

  • 在私有继承中,基类的公有成员和保护成员都将成为派生类的私有成员。
  • 在保护继承中,基类的公有成员和保护成员都将成为派生类的保护成员。

多重继承

class Deriver : public Basic1, private Basic2 {···};

标签:基类,Basic,函数,val,派生类,基础,C++,杂记,basic
From: https://www.cnblogs.com/torch-hxm/p/17800041.html

相关文章

  • 【面试专题】Java核心基础篇②
    目录1.接口和抽象类有什么区别?2.两个对象的hashCode()相同,则equals()也一定为true,对吗?3.说一说hashCode()和equals()的关系4.为什么要重写hashCode()和equals()?5.==和equals()有什么区别?6.简单聊聊什么是深拷贝?什么是浅拷贝?7.简单讲讲你对Java中的异常的理解?8.遇到过异常吗,如......
  • 10月31日线程基础
    目录线程基础线程的概念如果把操作系统当成一个工厂进程之间是竞争关系,线程之间是什么关系纠正概念进程与线程的区别是什么?线程基础线程的概念在操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程线程顾名思义,就是一条流水线工作的过程,可以这么想一条流水线必须属于......
  • 继续更新完善:C++ 结构体代码转MASM32代码
    一、需求分析在用MASM32编程更新完善SysInfo的网络连接信息,用到了MIB_TCP6TABLE_OWNER_MODULE结构体:typedefstruct_MIB_TCP6TABLE_OWNER_MODULE{DWORDdwNumEntries;MIB_TCP6ROW_OWNER_MODULEtable[ANY_SIZE];}MIB_TCP6TABLE_OWNER_MODULE,*PMIB_T......
  • 神经网络基础篇:史上最详细_详解计算图(Computation Graph)
    计算图可以说,一个神经网络的计算,都是按照前向或反向传播过程组织的。首先计算出一个新的网络的输出(前向过程),紧接着进行一个反向传输操作。后者用来计算出对应的梯度或导数。计算图解释了为什么用这种方式组织这些计算过程。在这个博客中,将举一个例子说明计算图是什么。让举一个比......
  • Opencascad开发(C++)-数据类型转换-Shape、Verterx和gp_pnt的转化
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录1、前言2、TopoDS_Shape与TopoDS_Vertex的转换2.1TopoDS_Shape到TopoDS_Vertex2.2TopoDS_Vertex到TopoDS_Shape3、TopoDS_Vertex与gp_Pnt3.1TopoDS_Vertex到gp_Pnt3.2gp_Pnt到TopoDS_Vertex1、前言在Open......
  • Opencascad(C++)-建模-创建有界直线段
    文章目录1、前言2、用gp_Lin创建一条直线2.1gp_Lin类成员函数2.2创建一条直线2.3运行结果3、创建一条有界的直线段3.1功能说明3.2函数说明3.2创建直线段的代码3.3测试效果1、前言在Opencascad开发时,经常会遇到创建直线的情况,采用gp_Line创建的直线段是无界的,如果想创建......
  • tdc++.so.6: version `GLIBCXX_3.4.29' not found
     001、python程序报错如下: 002、问题分析a、调用的是python程序b、libstdc++.so.6是c++标准库执行python程序时,需要调用c++标准库,libstdc++.so.6(lib=glib,6表示第6版),版本不匹配报错,无法找到:GLIBCXX_3.4.29。 003、确认调用的哪里的python程序(base)[b20223040......
  • c++ ftp上传下载
    #include<afxinet.h>intmain(){BOOLdRes,pRes;HINTERNEThInternet;HINTERNEThConnect;hInternet=InternetOpen("A3GSSample",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,INTERNET_FLAG_NO_CACHE_WRITE);if(NULL==hInternet){printf("Inter......
  • 云计算基础搭建-centOS7和VMware17
    软件:centOS7和VMware171、安装centOS2、查看机器名:hostnamectl3、修改机器名:hostnamectl set-hostname Controller_1  将机器名修改为Controller_14、添加IP地址   首先,查看虚拟机菜单:“编辑”-“虚拟网络编辑器”,查看NAT模式的子网,如:192.168.190.0 子......
  • C++基本输入输出
    C++基本输入输出C++标准库提供了一组丰富的输入/输出功能。C++的I/O操作发生在流中,流是字节序列。如果字节流是从设备(如键盘、磁盘驱动器、网络连接等)流向内存,这叫做输入操作。如果字节流是从内流向设备(如显示器、打印机、磁盘驱动器、网络连接等),这叫做输出操作。I/O库头文件......