C++经典问题:如果对象A中有对象成员B,对象B没有默认构造函数,那么对象A必须在初始化列表中初始化对象B?

对象成员特点总结:

(1)实例化对象A时,如果对象A有对象成员B,那么先执行对象B的构造函数,再执行A的构造函数。

(2)如果对象A中有对象成员B,那么销毁对象A时,先执行对象A的析构函数,再执行B的析构函数。

(3)如果对象A中有对象成员B,对象B没有默认构造函数,那么对象A必须在初始化列表中初始化对象B(原因:因为实例化A时,会先执行B的构造函数,再执行A的构造函数,如若对象B没有默认构造函数,即需要给B的构造函数传递参数才能调用,但是此时A的构造函数还没有执行,因此它还拿不到A构造函数的参数,所以先调用B的构造函数这个过程将无法进行。而初始化列表会先于构造函数的执行对对象成员进行初始化,因此不必再担心B的构造函数拿不到参数而无法执行的问题。因此如果B没有默认构造函数,那么对象A必须在初始化列表中初始化对象B.

       也许有人说 直接在a类的构造函数里“写死”b类构造函数的参数不就可以了吗,但这样的话不同a类对象里的b类对象的参数是固定的,而通过初始化列表的方式,则可以在定义a类对象时,为b类对象的构造参数传入参数,该参数是可以改变的,所以c++在设计的时候,就直接把前者摒弃掉,出现这种情况直接报错(个人看法

类A和B的关系就好比是汽车和零部件的关系,实例化类A就相当于产生汽车的过程,肯定要先生产零部件再组装生成汽车,因此构造的时候先构造对象成员类B,再构造类A。

销毁对象就跟销毁汽车的过程类似,必须先销毁汽车才能取其零部件,因此先调用类A的析构函数销毁类A,再销毁其对象成员类B。

具体由下面的代码演示,可直接RUN。

#include <iostream>using namespace std;
class Coordinate
{public:
Coordinate(int x, int y):m_iX(x),m_iY(y)//把a类的参数传递给b类
{cout<<"Coordinate() "<<m_iX<<","<<m_iY<<endl;
}~Coordinate(){cout<<"~Coordinate() "<<m_iX<<","<<m_iY<<endl;}// 打印坐标的函数
void printInfo()  
{cout<<"("<<m_iX<<","<<m_iY<<")"<<endl;
}
public:
int m_iX;
int m_iY;
};class Line
{public:Line(int x1,int y1,int x2,int y2):m_coordA(x1,y1),m_coordB(x2,y2){cout<<"Line()"<<endl;}~Line(){cout<<"~Line()"<<endl;}void printAB(){cout<<"("<<m_coordA.m_iX<<","<<m_coordA.m_iY<<")"<<endl;cout<<"("<<m_coordB.m_iX<<","<<m_coordB.m_iY<<")"<<endl;}public:Coordinate m_coordA;Coordinate m_coordB;
};
int main(void)
{Line * line = new Line(1,2,3,4);line->printAB();delete line;return 0;
}运行结果如下:Coordinate() 1,2
Coordinate() 3,4
Line()
(1,2)
(3,4)
~Line()
~Coordinate() 3,4
~Coordinate() 1,2

下面是直接“写死”的做法,编译也无法通过

#include <iostream>using namespace std;
class Coordinate
{public:
Coordinate(int x, int y):m_iX(x),m_iY(y)
{cout<<"Coordinate() "<<m_iX<<","<<m_iY<<endl;
}~Coordinate(){cout<<"~Coordinate() "<<m_iX<<","<<m_iY<<endl;}// 打印坐标的函数
void printInfo()
{cout<<"("<<m_iX<<","<<m_iY<<")"<<endl;
}
public:
int m_iX;
int m_iY;
};class Line
{public:Line(int x1,int y1,int x2,int y2){cout<<"Line()"<<endl;}~Line(){cout<<"~Line()"<<endl;}void printAB(){cout<<"("<<m_coordA.m_iX<<","<<m_coordA.m_iY<<")"<<endl;cout<<"("<<m_coordB.m_iX<<","<<m_coordB.m_iY<<")"<<endl;}public:Coordinate m_coordA(1,2);    //类A里直接定义B类对象(B类没有无参构造函数),而不通过初始化列表,这种写法是错误的Coordinate m_coordB(3,4);
};
int main(void)
{Line * line = new Line(1,2,3,4);line->printAB();delete line;//Coordinate m_coordA(1,2);    直接定义Coordinate类的对象就没有问题return 0;
}编译出错
topeet@ubuntu:~$ g++ test.cpp -o test
test.cpp:45: error: expected identifier before numeric constant
test.cpp:45: error: expected ‘,’ or ‘...’ before numeric constant
test.cpp:46: error: expected identifier before numeric constant
test.cpp:46: error: expected ‘,’ or ‘...’ before numeric constant
test.cpp: In member function ‘void Line::printAB()’:
test.cpp:41: error: ‘((Line*)this)->Line::m_coordA’ does not have class type
test.cpp:41: error: ‘((Line*)this)->Line::m_coordA’ does not have class type
test.cpp:42: error: ‘((Line*)this)->Line::m_coordB’ does not have class type
test.cpp:42: error: ‘((Line*)this)->Line::m_coordB’ does not have class type

参考文章:https://blog.csdn.net/hudfang/article/details/50511481

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384482.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JZ2440用U-Boot给Nand-Flash烧写程序时报错:NAND write: incorrect device type in bootloader ‘bootloader‘ is not

JZ2440开发板使用问题&#xff0c;U-Boot烧写程序到Nand Flash时报错&#xff1a;NAND write: incorrect device type in bootloader bootloader is not a number 这是因为分区名中u-boot&#xff0c;不是bootloader&#xff0c;而cmd_menu.c里用的是bootloader 可以执行&#…

韦东山衔接班——4.4_构建根文件系统之构建根文件系统

文章地址&#xff1a; https://blog.csdn.net/gongweidi/article/details/100086289?biz_id102&utm_term%E9%9F%A6%E4%B8%9C%E5%B1%B1%E8%A1%94%E6%8E%A5%E7%8F%AD&utm_mediumdistribute.pc_search_result.none-task-blog-2~blog~sobaiduweb~default-5-100086289&…

C++中const char *p和char const *p

const char *p;他的意思是p指向的目标空间的内容不可变化 例如定义char cA; p&c;则c的内容不可以变化.如cB;等一些企图改变变量c的值的做法都不行. 然而p仍然是动态的,就是它还可以指向别的空间,被赋予新的地址值,只是被他指向的目标空间的内容不可变化,如上面的c值始终为A…

qt 分割字符串的两种方法

https://blog.csdn.net/a724699769/article/details/62216435

【YOLO系列】YOLOv3代码详解(五):utils.py脚本

前言 以下内容仅为个人在学习人工智能中所记录的笔记&#xff0c;先将目标识别算法yolo系列的整理出来分享给大家&#xff0c;供大家学习参考。 本文仅对YOLOV3代码中关键部分进行了注释&#xff0c;未掌握基础代码的铁汁可以自己百度一下。 若文中内容有误&#xff0c;希望大家…

内核的Makefile与Kconfig关系解析

在子目录下的Kconfig里添加make menuconfig的选项&#xff08;如图一&#xff09;&#xff0c;并默认设置为y&#xff0c;make menuconfig的菜单里就会有该项并默认为选上状态&#xff0c;make menuconfig配置完之后在.config文件里就有该选项&#xff0c;并等于y&#xff08;如…

C语言extern的用法

在x.c文件里定义如&#xff1a;int x 100; 在x.h文件里声明如&#xff1a;extern int x; 然后在main.c里 #include "x.h"即可 或者直接在main.c里 extern int x; 而不使用#include "x.h"&#xff08;此时x.h里当然也不用extern int x;&#xff09;也…

C语言中.和->区别

结构体变量用 . 运算符来访问结构体的成员 struct A { int a; int b; };A object; object.a 1;指向结构体的指针用->来访问其指向的结构体的成员 A *point malloc(sizeof(struct A)); point->a 1;

Qt中定时器使用的两种方法

https://blog.csdn.net/qq_28877125/article/details/88389559

【深度】韦东山:一文看看尽linux对中断处理的前世今生

https://blog.csdn.net/thisway_diy/article/details/104848034

u-boot中filesize环境变量

U-Boot中的环境命令可以使用$(filesize)来确定刚下载(传输)得到的文件大小. 因为使用类似tftp命令传输文件后&#xff0c;会自动更新filesize环境变量。 如:setenv updaterootfs nand write.yaffs 30000000 200000 $(filesize) 这时如果printenv,会发现updaterootfsnand write…

make menuconfig选择m编译为驱动模块

之前看过各种文章说在make menuconfig的时候把某个选项配置为m&#xff0c;那就是要把该驱动编译为模块&#xff0c;但是在make uImage之后&#xff0c;在对应目录却没有生成.ko文件&#xff08;只有built-in.o&#xff09; 后来才知道是要在执行一遍make modules才会生成.ko文…

Linux下Modules的概念及使用详解

https://www.cnblogs.com/flintlovesam/p/5909782.html https://zhidao.baidu.com/question/270286794.html

QT使用SQLite数据库实现登录功能

QT实现用户登录功能&#xff08;MySQL&#xff09; https://blog.csdn.net/tianya_team/article/details/72566198 QT5中使用SQLite https://blog.csdn.net/weixin_41656968/article/details/80473137 Qt-多界面编程&#xff08;界面切换&#xff09; https://blog.csdn.n…

linux中pthread_join()与pthread_detach()详解

https://blog.csdn.net/weibo1230123/article/details/81410241

linux网络编程函数——地址复用setsockopt()

https://www.cnblogs.com/wujie2014/p/4029992.html

setsockopt()函数功能介绍

https://www.cnblogs.com/eeexu123/p/5275783.html

system函数和signal(SIGCHLD, SIG_DFL)的“固定搭配”

背景知识&#xff1a; 子进程先于父进程结束时&#xff0c;会给父进程发送SIGCHLD信号 如果 1、父进程没有忽略SGICHLD信号; 或…