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/683739/

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

(0)

大家都在看

  • 迭代器Iterator的使用方法(Java)

    迭代器是一种经典的设计模式。 用于在不需要暴漏数据是如何保存在数据结构中的细节的情况下,遍历一个数据结构。Collection接口继承自Iterable接口。所以说,实现了Coll…

    技术杂谈 2023年7月23日
    077
  • 2021.07.13 我们是这样崩的

    至暗时刻 2021年7月13日22:52,SRE收到大量服务和域名的接入层不可用报警,客服侧开始收到大量用户反馈B站无法使用,同时内部同学也反馈B站无法打开,甚至APP首页也无法打…

    技术杂谈 2023年5月30日
    090
  • HTML

    HTML5 一、标签 提示信息 placehod 锚链接: 顶部 回到顶部 空格:& nbsp; 序列 有序列表: java java 无序列表: java 自定义列表 d…

    技术杂谈 2023年6月21日
    083
  • Azure Service Fabric 踩坑日志

    近期项目上面用到了Azure Service Fabric这个服务,它是用来做微服务架构的,由于这套代码和架构都是以前同学留下来的,缺少文档,项目组在折腾时也曾遇到几个问题,这里整…

    技术杂谈 2023年5月31日
    0104
  • MAC 软件提示已损坏,需要移到废纸篓的解决方法

    解决方法一:允许任何来源的应用。在系统偏好设置里,打开”安全性和隐私”,将”允许从以下位置下载的应用程序”设置为”任何来…

    技术杂谈 2023年5月30日
    0112
  • 基于jsp+servlet的银行信贷管理系统。

    运行环境,jdk1.8或者jdk1.7、tomcat8或者tomcat8.5、mysql5.7、eclipse、myeclipse开发环境。 1、🐧1748741328,基于jsp…

    技术杂谈 2023年5月31日
    099
  • Https是否加密URL参数和Header中的信息?(转载)

    HTTPS 会加密 header 和 body,而 URL 中 hostname 之后的部分是存在于 header 中的。 但注意 hostname 一般是会被明文传送的,因为 S…

    技术杂谈 2023年5月31日
    0102
  • 三维数字沙盘+GIS = F3DGIS

    关键字:F3DGIS,数字沙盘,3D,GIS,电子沙盘 三维数字沙盘又称为虚拟沙盘、数字沙盘系统,是利用各种新技术,如:三维技术、地理遥控技术、虚拟现实技术、触控技术等,在计算机中…

    技术杂谈 2023年5月31日
    075
  • redhat 7.4从openssh7.6离线升级openssh8.4p1解决方法

    具体需求 这几天生产环境服务器又进行了安全扫描,每次都会报一下漏洞错误。虽然只有一个高危问题,但是每次看到ssh远程漏洞都很烧脑 “主要是里面坑太多了”,闲…

    技术杂谈 2023年6月21日
    0102
  • Oracle 备份与恢复 (Docker部署版)

    Oracle 备份与恢复 (Docker部署版) 一,宿主机设置定时备份脚本 1.检查Oracle容器是否正常运行 docker ps 2.进入容器,创建shell脚本 #orac…

    技术杂谈 2023年7月11日
    073
  • 特殊数表

    来自 command_block,为了适应 cnblogs 做了一些改动 . 以下是原文: 包括负数的二项式系数 (杨辉三角) ( \def\tinyS #1#2{\tiny\be…

    技术杂谈 2023年7月23日
    072
  • 记一次低危漏洞处理

    1、”Content-Security-Policy”头缺失 在网上查了关于这个响应头的说明,CSP相当于前台的白名单,用来限制网站内部一些资源获取的来源,…

    技术杂谈 2023年5月31日
    090
  • Mixin Messenger 源码解读 1 — — WCDB Swift

    Mixin Messenger 早期采用 FMDB 后来切换至 WCDB 沿用至今,一直比较可靠稳定,这里分享一下使用心得和功能扩展。 Mixin Messenger 是一个开源的…

    技术杂谈 2023年5月31日
    092
  • 下载ts文件

    迅雷批量下载ts:https://jingyan.baidu.com/article/9989c746653967b749ecfe2f.html 如何获取ts文件的下载地址,请看上…

    技术杂谈 2023年5月31日
    0113
  • 用于排队叫号系统的redis工具类

    分析 排队叫号系统的队列数据变化很频繁,因此可以考虑使用redis的list结构存储某一队列的数据,与前端采用websocekt连接,后端主动推送数据给前端,避免频繁轮询造成资源浪…

    技术杂谈 2023年7月23日
    076
  • JS——事件流与事件处理程序

    1.事件流:从页面中接收事件的顺序 1.1 IE :事件冒泡流1.2 Netscape :事件捕获1.3 DOM事件流 :事件捕获阶段——事件目标阶段——事件冒泡阶段DOM2级事件…

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