IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++子类对象的内存分布 -> 正文阅读

[C++知识库]C++子类对象的内存分布

C++子类对象的内存分布【奇牛学院】

1.前言

结合理论知识与自己的理解写的博客,主要是为了记录自己学习过程中的一些理解。如有错误,还请指正。

2.子类继承

当一个类继承了另一个类后,无论是什么继承类型,它继承的都是一样的东西。即继承所有父类成员变量与除父类构造函数与析构函数外的成员函数。但并不是父类中的东西只要子类继承了就能访问,子类是否能访问主要取决于父类成员在父类中的访问权限与子类继承父类的继承方式。

3.子类构造函数

在C++中,调用子类构造函数构造子类对象之前需先调用父类构造函数构造父类对象。

Son(string game,string name,int age) :Father("爸",25)    //在子类构造函数的实现后调用父类构造函数,Father是父类,Son是子类。

从正常逻辑来理解,面向对象思想中的类与对象是现实世界实体与概念的抽象表示。类具有的方法是现实事物行为的抽象表示,类的成员变量是现实事物属性的抽象表示。因此理解类的相关概念也能联系现实生活来理解。在这里也是一样的,把父类与子类的关系联系到现实中。肯定是先构造父类才能再构造子类,就像先有爸爸,然后这个爸爸才能生出一个儿子一样。

从代码角度看,子类对象会继承父类的成员方法,如果被继承的某个父类方法能被子类调用。那么需要先构造父类对象,用来初始化从父类继承的数据 。因为被调用的父类函数可能使用了父类的成员变量,所以需要先初始化再使用。要不然就可能是未知的值,造成程序未知的错误。

看一个例子:

#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include <Windows.h>

using namespace std;

class Father {

public:
	Father() {      //无参构造函数

	}

	Father(string name, int age) {      //有参构造函数

		this->name = name;
		this->age = age;
		cout << "调用父类构造函数" << endl;
	}

	int print() {           

		cout << "调用父类函数:" << endl;
		cout << "父类的名字:" << name << endl;
		cout << "父类的年龄:" << age << endl;

		return 0;
	}

	~Father() {
		cout << "调用父类析构函数" << endl;
	}

private:
	string name;
	int age;
};


class Son :public Father{

public:
	Son(string game,string name,int age) :Father() {   //使用无参构造函数构造父类

		this->age = age;
		this->name = name;
		this->game = game;
		cout << "调用子类构造函数" << endl;
	}

	int print1() {

		cout << "调用子类函数:" << endl;
		cout << "子类的名字:" << name << endl;
		cout << "子类的年龄:" << age << endl;
		cout << "子类爱玩的游戏:" << game << endl;

		return 0;
	}

	~Son() {
		cout << "调用子类析构函数" << endl;
	}

private:
	int age;
	string name;
	string game;
};


int main(void) {

	Son son("方舟", "儿", 15);

	son.print();
	//son.print1();

	cout << sizeof(son) << endl;

	system("pause");

	return 0;
}

在这里插入图片描述

我重载了父类的构造函数,一个是无参构造函数,一个是有参构造函数。并在子类构造函数中显示地调用父类的无参构造函数。因此父类对象的成员变量没有被初始化。所以在子类调用父类的print()方法时输出的都是未初始化的值。

另外,补充一点关于函数调用的规则。调用方法时,会先在子类定义的方法里找,如果找不到,就在父类定义的方法里找,如果还找不到,就发生错误。所以如果子类重写了父类的同名函数,那么子类对象调用该函数时,会调用子类的函数。

4.C++子类对象的内存分布

#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include <Windows.h>

using namespace std;

class DEMO {

public:
	DEMO() {

	}

	~DEMO() {

	}

private:
	int data;
	int age;
	int length;
};

int main(void) {

	DEMO demo;

	cout << sizeof(demo) << endl;

	system("pause");

	return 0;
}

在这里插入图片描述

在没有虚函数的情况下(以下都是在不考虑虚函数与内存对齐的情况下进行的讨论),子类对象的内存中只有其从父类继承的成员变量与其自己定义的成员变量(静态成员变量也不在对象内存中)。而没有成员函数的空间。另外,从父类继承的成员变量是存放在子类成员变量之前的。

一开始我也不太理解,成员函数也是类的成员,为什么对象中没有它的空间呢?

类是事物的抽象表示,成员方法是事物行为的抽象,成员变量是事物属性的抽象。对于一个类实例化的对象而言,它们具有的行为与属性是一样的。唯一不同的就是属性的值。

举个例子:
现在有一个人类类,他有吃饭,睡觉等方法,也有睡眠时间,饭量,身高,体重等属性。那么它实例化的对象也有吃饭,睡觉方法,睡眠时间,饭量,身高,体重属性。区分类实例化后对象的就是这些属性的值。如:不同的人每天睡眠时间是不一样的,身高,体重也是不一样的。

回到程序中,方法与变量在类的定义中已经有了并且所有对象都是一样的,不同的只是对象变量的值。类的成员方法都是存放在代码区的。当一个对象需要调用函数时,只需要去代码区找到,代入每个对象具体的变量值就行了(有点像函数调用)。而并不需要在每个对象中存放成员方法。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-28 22:43:27  更:2021-12-28 22:45:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:43:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码