C++之初识多态(Visual Studio 2019)

2023-05-16

此文章关于多态的代码全部是使用Visua Studio2019 (x86) 实现的,C++多态在不同编译器中的实现细节可能不同,所以部分情况下相同代码运行结果可能不同,在此声明。

目录

多态的概念

多态的定义与实现

虚函数

虚函数的重写

虚函数重写的两个例外

C++11 override & final

重载&重写&重定义

纯虚函数及抽象类

接口继承与实现继承

多态的原理

虚函数存在哪里?虚表存在哪里?

多态的原理

动态绑定与静态绑定

多继承下的虚函数表


多态的概念

多态,顾名思义,即多种形态。具体来说就是对于某个行为,不同的对象去完成该行为会产生不同的状态。

就像 “叫” 这个行为,猫来完成时其叫声是 “喵喵喵” ,而狗则是 “汪汪汪”。

还有坐公交车,老人和小孩坐车是免票,而其他人则是全价票。

同样的一个动作,不同的对象来执行,其实现的方法不同。

多态的定义与实现

多态是建立在继承基础上的,在不同的继承关系下的类对象,调用同一函数,产生不同的行为。

在C++中,继承体系下构成多态需要满足以下两个条件:

1.必须通过基类指针或引用调用虚函数。

2.被调用函数必须是虚函数,且派生类必须对基类虚函数进行重写。 

虚函数

虚函数:即被 virtual 修饰的类的成员函数。

class A {
public:
    virtual int add(int a, int b) {
        return a + b;
    }
}

使用virtual修饰虚函数时,只需要修饰类内部修饰即可。

class A {
public:
	virtual void print_1();
};

virtual void A::print_1() {
	cout << "1 : class A" << endl;
}

 

虚函数的重写

虚函数的重写指的是:派生类中有一个与基类完全相同的虚函数 (即派生类的虚函数与基类虚函数的返回值类型,参数列表,函数名完全相同),称子类的虚函数重写了基类的虚函数

class A {
public:
	virtual void print_1() {
		cout << "1 : class A" << endl;
	}
};

class B : public A {
public:
	virtual void print_1() {
		cout << "1 : class B" << endl;
	}
};

void func(A& a) {
	a.print_1();
}

int main() {
	A a;
	B b;
	func(a);
	func(b);
	return 0;
}

PS.子类重写父类虚函数时子类虚函数可以不加virtual关键字,这样也可以构成重写——继承后基类的虚函数被继承下来了,在派生类之中依旧保持虚函数属性。但是这种写法并不规范,并不建议使用。

虚函数重写的两个例外

1.协变

基类与派生类虚函数返回值不同

派生类重写基类虚函数时,若基类虚函数的返回类型是基类的指针或引用,新的返回类型是派生类的指针或引用,依旧可以构成重写。这样的重写被称为返回类型协变。

class A {
public:
	virtual A& print_1() {
		cout << "1 : class A" << endl;
		return *this;
	}
};

class B : public A {
public:
	virtual B& print_1() {
		cout << "1 : class B" << endl;
		return *this;
	}
};

需要注意的是,只有返回对应类型的指针或引用才会构成协变,单纯返回派生类或基类类型并不构成协变。

class A {
public:
	virtual A print_1() {
		cout << "1 : class A" << endl;
		return *this;
	}
};

class B : public A {
public:
	virtual B print_1() {
		cout << "1 : class B" << endl;
		return *this;
	}
};

2.析构函数的重写

基类与派生类析构函数函数名不同

当基类的析构函数为虚函数时,此时派生类的虚构函数只要定义,无论是否被virtual关键字修饰,都与基类析构函数构成重写。

class A {
public:
	virtual ~A() {
		cout << "A" << endl;
	}
};

class B : public A {
public:
	virtual ~B() {
		cout << "B" << endl;
	}
};


int main() {
	A* a = new B;
	delete a;
	return 0;
}

 

析构函数的重写最常见的应用便是基类指针指向派生类对象的情况下,如果我们所使用的派生类对象是从堆上 new 来的,那么,在没有重写析构函数的情况下,在基类对象 delete 时,只会调用基类的析构函数释放基类的空间,而派生类对象所占用的空间则不会被释放,就会导致内存泄漏。

C++11 override & final

1. override

在C++中,override关键字用来表示当前虚函数重写了基类虚函数。

在函数比较多,继承关系负责的情况下,override关键字可以起到提示编写者与其后继者某个函数重写了基类的虚函数——也代表这个函数不是派生类中定义的。

override关键字可以强制编译器去检查某个函数是否重写了基类虚函数,若否,则会报错。

class A {
public:

	virtual void print() {
		cout << "a" << endl;
	}
};

class B : public A {
public:
	virtual void print() override {
		cout << "b" << endl;
	}
};

 当override修饰的函数并非重写的基类虚函数时,会报错:

class A {
public:

	virtual void print() {
		cout << "a" << endl;
	}
};

class B : public A {
public:
	virtual void not_print() override {
		cout << "b" << endl;
	}
};

2.final

final用于修饰虚函数,表明该虚函数不能被重写

我们是可以直接用final修饰父类虚函数的,表明该虚函数不能被重写,但并不建议这样做,虚类既然与平常的类不同,其实例化时自然会比普通的类多一份开,而final只是指明了这个虚函数不可以被重写,但是虚类的相关开销依旧在。

class A {
public:
	int a;
	virtual void print() final{
		cout << "a" << endl;
	}
};

class B : public A {
public:
	int b;
	void a_print() {
		cout << "b" << endl;
	}
};

class C {
public:
	int a;
	void print() {
		cout << "a" << endl;
	}
};

class D : public C {
public:
	int b;
	void a_print() {
		cout << "b" << endl;
	}
};

int main() {
	B b;
	D d;
	b.b = 3;
	b.a = 2;
	d.a = 2;
	d.b = 3;
	while (0);
	return 0;
}

 

重载&重写&重定义

重载

将语义或功能相似的函数用同一个名字表示。

条件:

1.两个函数在同一个作用域

2.函数名相同

3.参数列表不同

4.返回值可以不同

重写 (覆盖)

覆盖是C++中多态的基础,使派生类可以重新定义基类的虚函数。

条件:

1.两个函数别属于基类成员函数与派生类成员函数

2.两个函数都必须是虚函数

3.函数名相同 (析构函数除外,至少看起来不同)

4.返回值类型相同 (协变例外)

5.参数列表相同

6.函数的访问权限可以不同 (如基类中的虚函数的访问权限是 private ,派生类中可以重写为public、protected)

重定义 (同名隐藏)

在继承体系中,子类与父类中有同名成员,子类可以屏蔽父类指针对子类中父类成员的直接访问。(但是可以使用 :: 访问父类成员)

条件:

1.在不同作用域

2.函数名相同

3.返回值可以不同

4.在继承体系中,只要不构成重写就是重定义

        1.参数相同时,基类没有关键字virtual修饰,基类的函数被隐藏

        2.参数不同时,无论有没有virtual关键字修饰,基类函数都被隐藏

class A {
	void print() {
		cout << "a" << endl;
	}
};

class B : public A {
public:
	int b;
	void print() {
		cout << "b" << endl;
	}
};

int main() {
	A a;
	B b;
	a.print();
	b.print();
	while (0);
	return 0;
}

 

纯虚函数及抽象类

在有些时候,基类的某些行为在没有被派生类重写之前会非常不明确,或者说,不合常理,不好定义。比如我们先前举过的例子——动物的 “叫” 这个行为,在动物这个基类中我们很难定义它具体是一种什么样的行为,表达方式是怎样的。我们是无法对这个行为做出具体的定义的,无法提供实现。但是作为一种 “共性” 我们又想要在基类中声明它。

于是乎,在虚函数的基础上,C++又提出了一种新的函数——纯虚函数。

在虚函数后面写上 = 0 ,则这个函数就是纯虚函数

包含纯虚函数的类叫做接口类——也被称为抽象类,抽象类不能实例化对象。

派生类继承抽象类后,如果不重写基类的纯虚函数,也无法实例化对象。

纯虚函数规定了派生类必须重写,同时也实现了接口继承。

class A {
public:
	virtual void print() = 0;
};

class B : public A {
public:
	int b;
	virtual void print() {
		cout << "b" << endl;
	}
};

int main() {
	B b;
	b.print();
	while (0);
	return 0;
}

接口继承与实现继承

普通函数的继承是一种实现继承,派生类继承了基类的函数,可以使用函数,这种继承继承的是函数的实现。

虚函数的继承则是一种接口继承,派生类继承的只是虚函数的接口,目的是为了重写,从而达成多态,继承的是一个接口。

所以,如果不实现多态,就不要把函数设置为虚函数。

多态的原理

class A {
public:
	int _a1;
	int _a2;

	virtual void study() {
		cout << "study" << endl;
	}

	A()
		:_a1(1)
		,_a2(2)
	{}
};


int main() {
	A a;
	return 0;
}

以上代码中,类A的实例化对象a在实例化后,其内存如上图所示,明显在我们所定义的变量a1, a2之前,还有着一串神奇的数字——00 75 9b 34。(据说有些编译器这玩意可能在后边)

单从表面上来看,它应该是一个指针。而实质上,它的确是一个指针。

在VS调试模式下的局部变量窗口中,我们可以很清楚的看到,这玩意还不是一个简单的指针,它是一个二级指针,指针名为 __vfptr (v——virtual f——function)我们通常称其为虚函数表指针。

 进一步将这个虚函数表指针展开来看

很容易看到,这个虚函数表指针指向的对象是一个函数指针,而函数指针指向的对象则是我们代码中所定义的虚函数——A::study(void)

一个含有虚函数的类中都至少有一个虚函数表指针,因为虚函数的地址要被存放到虚函数表中。

虚函数表也简称虚表

下面,我们将之放入继承体系之中来分析。

class A {
public:
	int _a1;
	int _a2;

	virtual void func1() {
		cout << "A::func1" << endl;
	}

	virtual void func2() {
		cout << "A::func2" << endl;
	}

	virtual void func3() {
		cout << "A::func3" << endl;
	}

	A()
		:_a1(1)
		,_a2(2)
	{}
};

class B : public A{
public:
	int _b1;
	int _b2;

	virtual void func1() {
		cout << "B::func1" << endl;
	}

	virtual void func2() {
		cout << "B::func2" << endl;
	}

	B()
		:_b1(3)
		,_b2(4)
	{}
};

int main() {
	A a;
	B b;
	return 0;
}

通过以上调试图片,可以看出

1.基类中有一个虚函数表指针,虚函数表中存储着三个基类虚函数的地址。

2.派生类对象中也有一个虚函数表指针,且该虚函数表由两部分构成——派生类重写的虚函数以及从基类中继承的虚函数。

3.基类对象与派生类对象的虚函数表中的内容是不同的,由于我们在派生类代码中重写了虚函数func1以及func2,所以派生类的虚函数表中对应位置存储的是被派生类重写后的B::func1(void)以及B::func2(void)。所以虚函数的重写也被称为覆盖,覆盖指的是虚表中虚函数的覆盖,派生类重写的虚函数地址覆盖了基类的虚函数地址。重写是语法层面的称呼,覆盖是原理层面的称呼。

4.虚函数表本质是一个存放虚函数指针的指针数组,一般情况下这个数组最后会放一个nullptr。

5.派生类虚表生成的过程如下:首先,将基类中虚表内容拷贝一份到派生类之中;而后,如果派生类重写了某个虚函数,用派生类自身的虚函数的地址覆盖虚函数表中基类虚函数的地址;最后,派生类将派生类之中新增的虚函数增加到虚函数表的最后。

6.虚函数表中只存放继承或派生类自身定义的虚函数,非虚函数不会被存放。

虚函数存在哪里?虚表存在哪里?

与普通的函数一样,虚函数存放于代码段中,只是它的指针被存储到了虚表之中。虚表并不存放于对象之中,对象中存储的是虚表指针。

虚表存放于代码段之中。(个人实力原因暂时无法证明)

多态的原理

分析了这么多,多态的原理究竟是什么?这里就需要用到我们之前屡试不爽的方法——通过基类指针/引用调用函数:

void Func(A* tmp) {
	tmp->func1();
}

int main() {
	A a;
	B b;
	Func(&a);
	Func(&b);
	return 0;
}

通过对以上代码进行反汇编,我们可以看到在使用基类引用调用虚函数时的操作如下: 

mov    eax,dword ptr [tmp]

tmp中存储的是基类对象的指针,将tmp中的值移动到eax寄存器中。

mov    edx,dword ptr [eax]

 将eax的值指向的内容存储到edx中,即将基类对象前4个字节(虚表指针)移动到edx中。

mov    ecx,dword ptr [tmp]

取tmp指针存储的值到ecx寄存器中 

mov    eax,dword ptr [edx]

取edx寄存器中的值指向的内容,相当于取了虚表的前四个字节,即虚表中存储的第一个虚函数的地址。如果我们此处调用的是fun2或者func3,则会在edx基础上偏移一定字节。 

call    eax

调用eax寄存器中存储的指针指向的函数。

动态绑定与静态绑定

静态绑定

静态绑定又被称为前期绑定早绑定,在程序编译期间便已经确定了程序的行为,也被称为静态多态

动态绑定

动态绑定又被称为后期绑定晚绑定,在程序运行期间,根据具体拿到的类型来确定程序的行为,调用具体的函数,也称为动态多态。 

多继承下的虚函数表

我们上文所主要讲解使用的是单继承情况下的虚函数表。这里我们就简单研究下如果在多继承体系下,虚函数表又会有怎样的不同。是将多个基类的虚函数表直接合为一个,还是分别存储与派生类对象中分属于不同基类的存储空间里。

class Base1 {
public:
	virtual void func1() { cout << "Base1::func1" << endl; }
	virtual void func2() { cout << "Base1::func2" << endl; }
private:
	int b1;
};
class Base2 {
public:
	virtual void func1() { cout << "Base2::func1" << endl; }
	virtual void func2() { cout << "Base2::func2" << endl; }
private:
	int b2;
};
class Derive : public Base1, public Base2 {
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
private:
	int d1;
};
typedef void(*VFPTR) ();
void PrintVTable(VFPTR vTable[])
{
	cout << " 虚表地址>" << vTable << endl;
	for (int i = 0; vTable[i] != nullptr; ++i)
	{
		printf(" 第%d个虚函数地址 :0X%x,->", i, vTable[i]);
		VFPTR f = vTable[i];
		f();
	}
	cout << endl;
}
int main()
{
	Derive d;
	VFPTR* vTableb1 = (VFPTR*)(*(int*)&d);
	PrintVTable(vTableb1);
	VFPTR* vTableb2 = (VFPTR*)(*(int*)((char*)&d + sizeof(Base1)));
	PrintVTable(vTableb2);
	return 0;
}

可能是之前对VS的编译器做过太多设置的修改,这个程序在Debug模式下运行会发生崩溃,崩溃原因是虚函数表末尾并没有按照我们预期的那样缀上一个nullptr。

但是在release模式下可以正常地运行,并得到一下结果: 

通过观察图示结果我们可以很直观的看到,多继承情况下,派生类重写的虚函数会放在第二个继承基类部分的虚函数表中,而未重写虚函数则会在第一个继承基类部分的虚函数表中。

同时,在多个基类中有相同的函数(函数名,返回值,参数列表)时,默认会重写先继承的基类中的对应函数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++之初识多态(Visual Studio 2019) 的相关文章

  • Visual Studio Code (vscode) 配置 C / C++ 环境

    Visual Studio Code vscode 配置 C C 43 43 环境 步平凡 博客园 在电脑安装软件管控严格的情况下 xff0c 想装VS装不了 xff0c 就装轻量版的VSCode了 以上写得很好 xff0c 照做即可 本人
  • Visual Studio中gets报错解决方法

    方法如下 xff1a 1 这是敲出gets后报的错 2 经过查找资料 xff0c 知道vs2015之后就不支持gets了 xff0c 变成了gets s xff0c 并且后面的括号中也不能单独写一个数组名 xff0c 还需加上数组内的个数
  • android Studio keytool' 不是内部或外部命令,也不是可运行的程序 或批处理文件

    android Studio keytool 39 不是内部或外部命令 xff0c 也不是可运行的程序 或批处理文件 遇到这个问题好久了 xff0c 一直没解决今天搜集了大量的资料 xff0c 有的说什么Java没配置好 xff0c 不是扯
  • Visual Studio Code语言设置为中文

    1 Visual Studio Code下载安装 https code visualstudio com 2 语言设置 2 1 快捷键 Windows Linux 快捷键是 xff1a ctrl 43 shift 43 p macOS 快捷
  • c语言编译运行程序,用visual c++ 运行C语言程序的过程

    用visual c 43 43 运行C语言程序的过程 下面是用visual c 43 43 运行C语言程序的过程的详细步骤及操作教程 xff0c 欢迎参考学习 一 xff1a 点击File new 新建 出现如下对话框 在该对话框中选择第一
  • SLAM综述:激光雷达与视觉SLAM(2019.10.12)

    本文基于https arxiv org pdf 1909 05214v2 pdf 进行阐述 xff08 其实差不多就是精简版翻译 xff09 第一节概述 第二节讲述激光SLAM xff1a 激光传感器 xff0c 开源系统 xff0c 深度
  • VsCode Studio的C/C++代码自动补全

    关于VsCode Studio的C C 43 43 代码自动补全 第一步 xff1a 需要下载VsCode中的C C 43 43 插件 如图 xff1a 插件下载后 xff0c 最好是重新启动一下VS 第二步 xff1a 找到设置 在输入框
  • Ubuntu 16.04下安装visual studio code

    一 坑和解决办法 很多帖子上写的方法都是使用命令方式 xff1a 1 先安装make sudo add apt repository ppa ubuntu desktop ubuntu make sudo apt get update su
  • CoppeliaSim ( vrep ) 与 c++ ( visual studio 2019)新建基本工程

    CoppeliaSim vrep 与 c 43 43 xff08 visual studio 2019 xff09 新建基本工程 文章目录 CoppeliaSim vrep 与 c 43 43 xff08 visual studio 201
  • Visual Assist 在VS2022中安装失败问题

    直接找到C Users xxxxx AppData Local Microsoft VisualStudio 17 0 xxxxx 文件夹 直接右击删除这个文件夹 注意要在VS2022关闭时再删除 可以先做一次备份 正常运行安装VA X S
  • Visual Studio中设置opencv环境

    图像处理的项目中 xff0c 每建立一个新的项目 xff0c 需要对环境重新设置 xff0c 本文记录一下自己在VS中设置环境的步骤 xff0c 也分享给相同的入门小白 本文侧重说明VS中调用opencv的环境设置步骤 xff0c open
  • Studio One 5机架设置一键切换效果通道

    Studio One是当前主流的直播机架软件 xff0c 操作非常方便 xff0c 但是呢默认情况下 xff0c 要切换效果时 xff0c 只能手动关闭一个效果的后 xff0c 再开另一个效果 xff0c 切换效果有点不方便 现在孤狼分享S
  • visual studio升级

    visual studio升级 概述升级步骤温馨提示 概述 有时处于开发要求或者安全要求 xff0c 需要将visual studio升级到最新的版本 本篇文章记录一下如何升级 升级步骤 1 找到visual studio的安装路径下的安装
  • A review of visual SLAM methods for autonomous driving vehicles

    自主驾驶车辆的视觉SLAM方法回顾 原论文在文章末尾 摘要 xff1a 自主驾驶车辆在不同的驾驶环境中都需要精确的定位和测绘解决方案 在这种情况下 xff0c 同步定位和测绘 xff08 SLAM xff09 技术是一个很好的研究解决方案
  • Photoshop cc2019 破解教程

    Photoshop cc2019 破解教程 内含破解器 1 下载替换文件 Photoshop exe 链接如下 链接 https pan baidu com s 11XrnXWvGsnQ7YMbIMb49Lw 提取码 t9ol 2 打开Ph
  • How to Install Android Studio under Ubuntu 16.04

    If you find difficulties installing Android Studio under Ubuntu 16 04 1 LTS Xenial Xerus you can follow this tutorial th
  • Ubuntu12.04下配置Android studio开发环境

    之前一直在Windows下面进行Android的开发任务 Ubuntu也是用的虚拟机 但是最近代码编译了 刷机总是出现一些莫名其妙的问题 于是决定进行一次大迁移 把虚拟机放弃了 直接使用Ubuntu系统 但是这样子要把studio里面的代码
  • 2019年厦门大学计算机系夏令营经历

    2019 07 12 2019 07 15 厦门大学信息学院夏令营 计算机系笔试 上机 面试 一 笔试 数据结构 2019 07 13 填空题 一空三分 顺序存储 将一个数插到数字i下标的前面 需要移动多少个元素 m数组和n数组 最坏情况下
  • Intellij IDEA 2019无法联网,无法下载插件问题解决办法

    Intellij IDEA 2019无法联网 无法下载插件问题解决办法 非法不多说直接上图 第一步 第二步 2019 2 之后没有这一步 第三步 记得重启哦 lt 完 gt
  • android studio从git上克隆项目显示the directory already exists and it is not empty

    英文的意思能看懂 文件夹已存在并且不为空 但是网上百度了一下貌似没有完完整整是这句话的问题 我还纳闷怎么克隆不下来 我是想把项目克隆下来到workspace里面 workspace里面本来就还有其他项目在 原来克隆操作不会帮你生成跟目录 你

随机推荐

  • Redis学习笔记(狂神说)

    狂神视频地址 xff1a https www bilibili com video BV1S54y1R7SB Nosql概述 为什么要用Nosql 1 单机Mysql的年代 DAL xff1a 数据库访问层 在90年代 xff0c 一个基本
  • gazebo地图构建

    搭建地图环境是gazebo的基础功能 打开gazebo 可以在终端输入指令 打开的时候一定要有sudo xff0c 不然有可能在后面保存的时候出现画面卡住不动的情况 span class token operator span sudo g
  • Linux Ubuntu18.04安装微信

    最近做双系统 xff0c 在Ubuntu里下载微信时发现微信没有光网里没有开发Linux版本的微信 xff0c 找到了一些使用网页版登录微信的教程 xff0c 按着网上的教程做下来会的到一个如下的微信图标 打开扫描二维码后无法登录 可以在其
  • 虚拟机Ubuntu18.04 使用usb_cam调用笔记本摄像头

    虚拟机搭载Ubuntu18 04调用笔记本的摄像头 xff08 踩坑以及解决方法 xff09 一 建立工作空间 xff08 略 xff09 这里我建立的工作空间名称是catkin ones 二 下载usb cam包并进行编译 git clo
  • 关于UDP双向通信原理解释与范例

    注 本文不提供UDP通信的头文件 OK Let s do it 首先 我们需要了解什么叫做UDP xff0c 之前博主有些过TCP的通信范例 xff0c 我们可以了解到TCP的通信是一个稳定的 xff0c 可以进行双边通信的方式 同样附带上
  • windows10引导盘修复

    Windows修复引导项 前几天做双系统 xff0c 在使用Easybcd制作引导项时误删win10原本的引导项 xff0c 导致无法开机 xff0c 但是我可以通过磁盘直接启动linux 记录以下修复过程 在Linux里使用工具检查恢复
  • 局部路径规划:DWA算法

    一 概述 DWA算法是全称是Dynamic Window Approach 是在ROS中应用比较广泛的局部路径规划算法 主要作用是接受全局路径规划器生成的路径 xff0c 里程计信息 xff0c 地图信息等 xff0c 通过局部路径规划器将
  • ORB_SLAM2地图保存

    ORB SLAM2地图保存 在安装好orb slam2后按照教程中的方法做了地图构建的实验 xff0c 但是当地图达到想要的标准之后 xff0c 却发现没有办法保存地图 xff0c 查看ORB SLAM2源码发现在System h中有如下一
  • ros仿真小车

    ros仿真小车 补全前面博客中缺少的一些部分关于前面博客中的robotcar 本文也可单独食用 xff09 创建工作空间并初始化 span class token function mkdir span p catkin ws src sp
  • 【2023电赛备赛】msp430f5529学习笔记(一)

    写在前 本人目前是大二在读生 xff0c 第一次参加电赛 xff0c 准备不充分 xff0c 结果熬了四天 xff0c 最后成绩却不如人意 有51和32的基础 xff0c 然后想立一个flag系统的学习一下主打超低功耗的msp430f552
  • C语言经典题:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

    include lt stdio h gt 通过for循环将变量i j k的取值锁定在1 xff0c 2 xff0c 3 xff0c 4之间 int main int num 61 0 int i 61 0 j 61 0 k 61 0 fo
  • 单词逆序输出(c语言)

    int main int l j 61 0 int tmp 61 0 存储输入字符串的数组 char arr 100 61 34 i love beijing 34 用来存储输出字符串的数组 char arr2 100 输入字符串 gets
  • 进程虚拟地址空间

    关键词 xff1a 进程虚拟地址空间 xff0c 进程描述符 xff0c 页表 xff0c 分段式 xff0c 段页式 在进入正式的内容之前 xff0c 我们先了解一个重要的概念 进程描述符PCB 在Linux操作系统中 xff0c 描述进
  • 简单了解函数调用过程

    什么是栈帧 C C 43 43 程序的基本组成部分是函数 当程序在运行时 xff0c 每个函数每次调用都会在调用栈上维护一个独立的栈帧 xff0c 栈帧中维持着函数所需的各种信息 栈帧也叫过程活动记录 xff0c 是编译器用来实现过程 函数
  • 错题汇总1

    1 以下程序的运行结果是 xff08 xff09 int main void printf 34 s 5 3s n 34 34 computer 34 34 computer 34 return 0 A computer puter B c
  • 使用C/C++制作信息管理系统(demo)

    要求 xff1a 在windows环境下使用Vistual studio以C C 43 43 语言编译一个具有基础框架的客户信息管理系统 必须使用到封装 继承 map容器 SQL数据库技术 我 是 分 割 线 未经过UI处理的基础系统功能效
  • 错题汇总2

    1 下列程序的打印结果是 char p1 15 61 34 abcd 34 p2 61 34 ABCD 34 str 50 61 34 xyz 34 strcpy str 43 2 strcat p1 43 2 p2 43 1 printf
  • C++之继承初识(不包含虚拟继承)

    C 43 43 是一种面向对象的语言 xff0c 而面向对象 xff0c 有着三大特征 封装 xff0c 继承 xff0c 多态 关于封装 xff0c 在我的其它博客中已经有过简单的介绍了 这里我将简单叙述一下面向对象的三大特征之二 继承
  • C++之虚拟继承与继承的小总结

    本来是想将虚拟继承的部分写在上一篇的 xff0c 但是虚拟继承的分析实在有些复杂 xff0c 为了方便我自己回顾 xff0c 就干脆单写一篇吧 我们之前说过了 xff0c 虚拟继承可以解决菱形继承的二义性以及数据冗余的问题 xff0c 实际
  • C++之初识多态(Visual Studio 2019)

    此文章关于多态的代码全部是使用Visua Studio2019 x86 实现的 xff0c C 43 43 多态在不同编译器中的实现细节可能不同 xff0c 所以部分情况下相同代码运行结果可能不同 xff0c 在此声明 目录 多态的概念 多