cpp创建对象的多种形式

1 使用非默认构造函数来创建对象的几种形式

Person person = Person("binny1", 26);

这种方式创建对象,C++标准允许编译器使用两种方式来执行:

1、会创建一个临时对象,然后将临时对象复制到 person中,并丢弃临时对象。此时,将为临时对象调用析构函数,正如上面的结果。

编译器肯能立即删除临时对象,也可能过一会儿。

Person person2("binny2", 27);//会创建临时对象

这种格式更紧凑,它与显示调用等价。

Person *pPerson3 = new Person("binny3", 8);//不会创建临时对象

这条语句创建一个Person 对象,将其初始化为参数列表提供的值,并将该对象的地址赋给 pPerson指针。

这种情况下对象没有名字,但可以使用指针来管理对象。

如果编译器支持C++11,则可以用时列表初始化。只要提供的大括号列表中的数据与某个构造函数的参数列表匹配就可以。

Person person4 = {"binny4", 26};//c++11,会创建临时对象
Person person5{"binny5", 26};//c++11,会创建临时对象
Person *pPerson6 = new Person{"binny6", 26};//c++11,不会创建临时对象
Person person{};//与默认构造函数相匹配

2、使用默认构造函数来创建对象

Person person = Person();
Person person;

隐式调用默认构造函数,不要使用圆括号

头文件

c// // // Created by Biter on 2019/10/16.</p> <p>//</p> <h1>include</h1> <h1>ifndef NDK_PERSON_H</h1> <h1>define NDK_PERSON_H</h1> <p>using namespace std;</p> <p>class Person {</p> <p>private: char *mName; int mAge; public: Person();</p> <pre><code>Person(int age); Person(char *name, int age); void setName(char *name); void setAge(int age); char * getName(); int getAge(); ~Person(); </code></pre> <p>};</p> <h1>endif //NDK_PERSON_H</h1> <pre><code> ## 头文件的实现
//
// Created by Biter on 2019/10/16.

//

#include "../includes/Person.h"

Person::Person() {
mName = "biter";
mAge = 26;
}

Person::Person(char *name, int age) {
mName = name;
mAge = age;
cout << "Hello " << mName << endl;
}

Person::Person(int age) {
mAge = age;
}

void Person::setName(char *name) {
mName = name;
}

void Person::setAge(int age) {
mAge = age;
}

int Person::getAge() {
return mAge;
}

char *Person::getName() {
return mName;
}

Person::~Person() {
cout << "Bey " << mName << endl;
} ## 项目代码
//
// Created by Biter on 2019/10/15.

//
#include
#include "includes/Person.h"

int main() {

//第一种创建对象的方式
Person person1 = Person("binny1,显示调用构造函数", 26);
// //第二种创建对象的方式
Person person2("binny2,隐式调用构造函数", 27);
// //第三种创建对象的方式
Person *pPerson3 = new Person("binny3,动态创建对象", 8);

//c++11 列表初始化
Person person4 = {"binny4,显示列表初始化", 26};
Person person5{"binny5,隐式列表初始化", 26};
Person *pPerson6 = new Person{"binny6,动态列表初始化", 26};

std::cout << "person1 name = " << person1.getName() << std::endl;
std::cout << "person2 name = " << person2.getName() << std::endl;
std::cout << "person3 name = " << pPerson3->getName() << std::endl;
std::cout << "person4 name = " << person4.getName() << std::endl;
std::cout << "person5 name = " << person5.getName() << std::endl;
std::cout << "person6 name = " << pPerson6->getName() << std::endl;

Person person7 = 26;
person7.setName("p9");
std::cout << "p9.getAge() = " << person7.getAge() << std::endl;
return 0;
}

运行结果

C++提供了多种对象的创建方式,每次创建对象时(包括使用new动态分配内存),C++都是用类的构造函数。

从运行结果看出,动态创建对象的时候,没有调用析构函数。

小括号,老语法

Person person();//默认构造函数
Person person2("binny2", 27);//非默认构造函数
Person person1 = Person("binny1,显示调用构造函数", 26);
Person *pPerson3 = new Person("binny3,动态创建对象", 8);

大括号,新语法

Person person5{"binny5,隐式列表初始化", 26};
Person person4 = {"binny4,显示列表初始化", 26};
Person *pPerson6 = new Person{"binny6,动态列表初始化", 26};

无括号

如果构造参数只有一个参数,则可以将对象初始化为一个与该构造器参数类型相同的值,此时该构造将被调用。

Person person7 = 26;
std::cout << "p9.getAge() = " << person7.getAge() << std::endl;

由于没有初始化

,则析构函数被调用的时候输出乱码。修改如下:

Person person7 = 26;
p9.setName("p9");
std::cout << "p9.getAge() = " << person7.getAge() << std::endl;

C++构造函数初始化列表

构造函数的一项重要功能是对成员变量进行初始化,为了达到这个目的,可以在构造函数的函数体中对成员变量一一赋值,还可以采用 &#x521D;&#x59CB;&#x5316;&#x5217;&#x8868;

C++构造函数的初始化列表使得代码更加简洁。

#include
using namespace std;

class Student{
private:
    char *m_name;
    int m_age;
    float m_score;
public:
    Student(char *name, int age, float score);
    void show();
};

//采用初始化列表
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
    //TODO:
}
void Student::show(){
    cout< show();

    return 0;
}

如本例所示,定义构造函数时并没有在函数体中对成员变量一一赋值,其函数体为空(当然也可以有其他语句),而是在函数首部与函数体之间添加了一个冒号 :,后面紧跟 m_name(name), m_age(age), m_score(score)语句,这个语句的意思相当于函数体内部的 m_name = name; m_age = age; m_score = score;语句,也是赋值的意思。

使用构造函数初始化列表并没有效率上的优势,仅仅是书写方便,尤其是成员变量较多时,这种写法非常简单明了。

初始化列表可以用于全部成员变量,也可以只用于部分成员变量。下面的示例只对 m_name 使用初始化列表,其他成员变量还是一一赋值:

Student::Student(char *name, int age, float score): m_name(name){
    m_age = age;
    m_score = score;
}

注意,成员变量的初始化顺序与初始化列表中列出的变量的顺序无关,它只与成员变量在类中声明的顺序有关。请看代码:

#include
using namespace std;
class Demo{
private:
    int m_a;
    int m_b;
public:
    Demo(int b);
    void show();
};
Demo::Demo(int b): m_b(b), m_a(m_b){ }
void Demo::show(){ cout<
运行结果:
2130567168, 100

在初始化列表中,我们将 m_b 放在了 m_a 的前面,看起来是先给 m_b 赋值,再给 m_a 赋值,其实不然!成员变量的赋值顺序由它们在类中的声明顺序决定,在 Demo 类中,我们先声明的 m_a,再声明的 m_b,所以构造函数和下面的代码等价:

Demo::Demo(int b){
    m_a = m_b;
    m_b = b;
}

m_a 赋值时, m_b 还未被初始化,它的值是不确定的,所以输出的 m_a 的值是一个奇怪的数字;给 m_a 赋值完成后才给 m_b 赋值,此时 m_b 的值才是 100。

obj 在栈上分配内存,成员变量的初始值是不确定的。

初始化 const 成员变量

构造函数初始化列表还有一个很重要的作用,那就是初始化 const 成员变量。初始化 const 成员变量的唯一方法就是使用初始化列表。例如 VS/VC 不支持变长数组(数组长度不能是变量),我们自己定义了一个 VLA 类,用于模拟变长数组,请看下面的代码:

class VLA{
private:
    const int m_len;
    int *m_arr;
public:
    VLA(int len);
};
//必须使用初始化列表来初始化 m_len
VLA::VLA(int len): m_len(len){
    m_arr = new int[len];
}

VLA 类包含了两个成员变量, m_lenm_arr 指针,需要注意的是 m_len 加了 const 修饰,只能使用初始化列表的方式赋值,如果写作下面的形式是错误的:

class VLA{
private:
    const int m_len;
    int *m_arr;
public:
    VLA(int len);
};
VLA::VLA(int len){
    m_len = len;
    m_arr = new int[len];
}

Original: https://www.cnblogs.com/burner/p/cpp-chuang-jian-dui-xiang-de-duo-zhong-xing-shi.html
Author: 浪客禅心
Title: cpp创建对象的多种形式

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/606502/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 关于Python, ftplib模块中的cwd()进入含中文目录失败的问题

    使用Python的ftplib模块连接ftp服务器时, 使用cwd()连接含中文的目录, 报错 : UnicodeEncodeError: ‘latin-1&#8217…

    Linux 2023年6月6日
    0101
  • shell中的##*,%%*问题

    假设我们定义了一个变量为:file=/dir1/dir2/dir3/my.file.txt 可以用${ }分别替换得到不同的值:${file#/}:删掉第一个 / 及其左边的字符串…

    Linux 2023年5月28日
    064
  • shell编程-杨辉三角简单实现

    shell编程-杨辉三角问题: 概述:中国古代数学家在数学的许多重要领域中处于遥遥领先的地位。中国古代数学史曾经有自己光辉灿烂的篇章,而杨辉三角的发现就是十分精彩的一页。杨辉三角形…

    Linux 2023年6月7日
    094
  • Nginx基础入门篇(2)—编译参数介绍

    查看命令 nginx -V nginx version: nginx/1.22.0 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (…

    Linux 2023年6月6日
    0117
  • [20220104]in list 几种写法性能测试.txt

    [20220104]in list 几种写法性能测试.txt –//以前写过几种in list的写法,从来没有测试过这几种方法的性能测试看看. 1.环境:SCOTT@b…

    Linux 2023年6月13日
    052
  • Redis 持久化

    Redis 提供了一系列不同的持久性选项: RDB(Redis 数据库):RDB 持久性以指定的时间间隔执行数据集的时间点快照。 AOF(Append Only File):AOF…

    Linux 2023年5月28日
    072
  • Redis 事务与锁

    基本操作 事务的基本操作 开启事务,设定事务的开启位置,此指令执行后,后续的所有指令均加入到事务中 multi 取消事务,终止当前事务的定义,发生在 multi 之后,exec 之…

    Linux 2023年5月28日
    075
  • Lua集成Redis及Nginx

    1 Lua介绍 Lua是一门以其性能著称的脚本语言,被广泛应用在很多方面。Lua一般用于嵌入式应用,现在越来越多应用于游戏 当中,魔兽世界,愤怒的小鸟都有用到。优势 Lua极易嵌入…

    Linux 2023年6月13日
    064
  • 云主机实现校园网使用网络

    下载SoftEther 虚拟专用网络 Server 管理工具和 Open虚拟专用网络 GUI工具 配置云主机 tar -zxvf softether-vpnserver-v4.28…

    Linux 2023年6月8日
    078
  • Android recovery支持adb shell

    Android recovery支持adb shell 近期开发过程注意到recovery不支持adb shell。为了便于调试方便,决定添加此功能。 刚開始我们採用的是user版…

    Linux 2023年5月28日
    090
  • 机器学习导引

    三种范式 常常定义一种损失函数,对训练集进行处理时使其最小化。该函数代表了系统输出对于正确输出的错误率,因为训练集的给定的输出是正确的 学习数值型预测函数,比如房价预测模型 在训练…

    Linux 2023年6月7日
    063
  • Linux编译安装、压缩打包与定时任务服务

    一、编译安装 即使用源代码编译安装的方式,编译打包软件。特点: 可以自定制软件; 可以按需构建软件; 编译安装案例 1、下载源代码包(这里以Nginx软件包源代码为例) wget …

    Linux 2023年5月27日
    080
  • MHA实现MySQL的高可用性

    对主节点进行监控,可实现自动故障转移至其它从节点;通过提升某一从节点为新的主节点,基于主从复制实现,还需要客户端配合实现。 目前MHA主要支持一主多从的架构,要搭建MHA,要求一个…

    Linux 2023年6月7日
    0100
  • Docker 安装 ElasticSearch 及失败解决方法[Ubuntu 20.04]

    1. 下载 ElasticSearch 最开始使用 docker search命令搜索后,就直接使用 docker pull命令拉取镜像,但没想到拉取失败,后来到官网看了看,原来没…

    Linux 2023年6月14日
    0126
  • Mysql Date操作

    根据format字符串格式化date值。 下列修饰符可以被用在format字符串中: %W 星期名字(Sunday……Saturday) %D 有英语前缀的月份的日期(1s…

    Linux 2023年6月7日
    061
  • 国产化之虚拟ARM64-CPU安装银河麒麟操作系统

    背景 某个项目需要实现基础软件全部国产化,其中操作系统指定银河麒麟v4,CPU使用飞腾处理器。我本地没有这个国产的处理器,但飞腾是基于 _ARMv8_架构的64位处理器,所以理论上…

    Linux 2023年5月27日
    0305
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球