首页 > 其他分享 >1-1 对象特性

1-1 对象特性

时间:2023-08-05 23:12:41浏览次数:34  
标签:函数 对象 特性 Person int 拷贝 构造函数

1 new和delete

  • new的返回值是对应数据类型的地址,数组时返回首地址
  • delete之后再让指针指向NULL是一个很好的习惯
int *p = new int(10);
delete p;
int *arr = new int[10];//开一个10个元素的数组,访问数组时与正常数组一样使用,例如元素arr[3]
delete[] arr;//释放数组时加一个中括号 

2 引用

  • 给变量起别名,引用和原来的变量操作的是同一块内存地址。数据类型 &别名 = 原名
  • 引用做函数参数,即形参作为了实参的别名,可用形参修饰实参,其比地址传递效率更高
1.按值传递
2.按地址传递(形参可修饰实参)
3.按引用传递(形参可修饰实参)
void swap(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}
简单的swap函数即可验证

引用效率高的三个原因:
1.无需解引用:使用引用作为函数参数时,不需要进行指针解引用(*)操作。

2.无需空指针检查:引用作为函数参数时,不会出现空指针的情况。因为引用必须在声明时进行初始化,而且不能被重新赋值为nullptr或空指针。而指针作为函数参数时,需要进行空指针检查,以确保指针有效,否则可能导致错误。

3.代码可读性:引用作为函数参数可以提高代码的可读性和易用性。它可以让函数调用看起来更自然,更直观,并且减少了在使用指针时可能出现的繁琐的语法。
 

  • 常量引用:主要用来限制形参,防止函数中误操作影响实参,如const int &
int &a = 10;//不允许,引用要绑定的是左值,要对合法空间进行操作
const int &a = 10;//允许

 

注意事项:

  • 引用必须初始化。如:int &b;//错误
  • 引用一旦初始化不可更改。它已经作为一个变量的别名时,就不允许再做其它变量的别名了。(本质上就是一个指针常量)
  • 不要返回局部变量的引用,编译器不会报错这类问题,但是在使用这个返回值时会出问题。局部变量在函数结束后就应该被释放掉了,使用这样的引用相当于操作非法空间了。
int& swap(void)//不要这样做,如果要返回a,必须加上static来延长生命周期
{
    int a = 20;
    return a;
}

3 函数默认参数与占位参数

默认参数:允许在函数声明中为一个或多个参数指定默认值。当调用函数时,如果没有为这些参数提供实参,则会使用默认值作为参数的值。

void printMessage(const std::string& message, int count = 1) {
    for (int i = 0; i < count; ++i) {
        std::cout << message << std::endl;
    }
}

int main() {
    printMessage("Hello"); // 使用默认参数 count = 1
    printMessage("Hi", 3); // 提供实参,count = 3
    return 0;
}

 
占位参数:通常用于表示需要一个参数,但不关心其值、类型等

4 函数重载

允许函数名相同,提高复用性

函数重载条件;

  • 同意作用域下
  • 函数名称相同
  • 函数参数类型不同,或者顺序不同,或者个数不同
    注:返回值不可作为重载条件,尽量避免占位参数的函数重载

5 封装

封装是一个很典型的区别于C的特性,它允许数据(属性)和函数(行为)放在一起,可提供接口,限制属性

封装的权限控制:

  • 私有:类内的成员可以访问,类外不可以(继承时子类不可访问基类私有)
  • 保护:类内的成员可以访问,类外不可以(继承时子类可以访问基类的保护)
  • 公共:类内类外都可以访问
    C++中struct和class的区别只有默认访问权限不同

6 对象特性

1 构造与析构

分别用于对象的初始化和清理,自己不实现的时候,编译器会帮助实现

构造函数:

  • 语法:类名(){}
  • 允许有参数,可重载
  • 创建对象时,自动调用一次

析构函数:

  • 语法:~类名(){}
  • 不允许有参数,不可重载
  • 对象销毁前调用,一般用于清理在堆区开辟的内存

2 构造函数的调用以及调用

按参数分:有参构造和无参构造
按类型分:普通构造与拷贝构造

拷贝构造函数:
用于从其它已有的相同类型对象身上拷贝出一份一模一样的数据

Person (const Person &p){}

 
三种调用方式
1.括号法
主要用于传参

Person p1;//默认构造函数,不需要加括号
Person p1(10);//有参构造
Person p2(p1);//拷贝构造函数

2.显示法(几乎不用)
几乎不用,过于繁琐

Person p2 = Person(10);//等式右边相当于一个匿名对象
Person p3 = Person(p3);//拷贝构造

3.隐式法(几乎不用)

Person p2 = 10;
Person p3 = p2;

3 拷贝构造函数使用时机

  • 使用一个已创建的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象

值传递方式调用:

void doWork(Person p){
}

void test(){
  Person p;
  dowork(p);//在传参的过程中调用了拷贝构造函数
}

以值方式返回局部对象
在调用这个函数进行赋值时会调用拷贝构造函数

Person doWork2()
{
    Person p1;
    return p1;
//注意这里返回的并不是真的p1,而是p1',是一个新对象,若要返回p1,函数类型应该是Person&
}

4 构造函数调用规则

  • 每创建一个类,编译器都会为我们自动添加三个函数,默认构造,析构函数,拷贝构造。
  • 如果我们只写了有参构造,编译器将不再提供默认无参构造,但任然提供拷贝构造
  • 如果我们写了拷贝构造,编译器将不再提供其它构造函数
    默认->有参构造->拷贝构造,后面任意一个实现了,前面的都不会再由编译器提供

这就是为什么我们看到好多程序中会同时写上多个构造函数。

5 深拷贝与浅拷贝

浅拷贝:像编译器提供的这样的默认拷贝构造中,就只是简单的赋值拷贝操作。对于在堆区开辟地址的变量,这种浅拷贝使得两个对象的成员指向了同一块堆区地址,最后在调用析构释放的时候会造成堆区内存重复释放,即内存的非法操作。

深拷贝:在堆区重新申请空间,进行拷贝构造,解决浅拷贝出现的问题。解决方式就是自己实现拷贝构造函数,对于要拷贝的变量重新用new申请一块内存来存放。
如果属性有在堆区开辟的,一定要自己提供一个深拷贝构造函数

6 初始化列表

语法:构造函数():属性1(值1),属性2(值2)...{}
方便我们使用构造函数进行值得初始化

Person(int a, int b, int c):m_A(a), m_B(b), m_C(c){}

7 静态成员

在成员变量前加上static关键字就成为静态成员,这是专属于类的,且非静态成员函数也是属于类的,只有非静态成员变量才是属于对象的,可以用sizeof来了解

静态成员变量

  • 不属于某一个对象,所有对象共享同一份数据,即有一个对象对这个成员变量进行了修改,另外的对象拥有的也是这个修改过的数,所有对象的这个静态成员变量的值应当是一样的
  • 在编译阶段分配内存
  • 类内声明,类外初始化,如:Persson::m_A = 10;
  • 两种访问方式:通过对象访问,通过类访问

静态成员函数

  • 所有对象共享一个函数
  • 静态成员函数只能访问静态成员变量,因为静态成员变量在内存中只有一份,而其它非静态成员变量无法区分是哪一个对象的。
  • 两种访问方式:通过对象、通过类名

8 this指针

C++中对于成员函数只有一份实例,无论是静态还是非静态的,多个对象调用这个函数的时候会共享这一块代码,C++用this指针来区分是哪一个对象在调用。

this指针隐含在每一个非静态成员函数内,指向调用该成员函数的对象,其用途为:

  • 当形参和成员变量同名时,用this指针来区分,this指示的就是要被赋值的成员变量
  • 在类的非静态成员函数中返回对象本身,可以使用return *this
Person& PersonAddAge(Person &p)
{
  this->age += p.age;
  return *this;//返回这个对象

9 空指针访问成员函数

为了避免我们使用空指针访问,好的办法应该是这样的

if(this == NULL) return;

10 const修饰成员函数

常函数:

  • 成员函数加const后变为常函数
  • 常函数内不可以修改成员属性,除非加了关键字mutable
void addAge() const{}//常函数

常对象:

  • 声明对象前加const,不允许修改成员
  • 常对象只能调用常函数,因为普通函数能修改成员变量

标签:函数,对象,特性,Person,int,拷贝,构造函数
From: https://www.cnblogs.com/dreamer-q/p/17558740.html

相关文章

  • JAVA SE基础《八》 ---- 面对对象编程
    目录一、面向对象编程快速入门二、深刻认识面向对象三、对象在计算机中的执行原理四、类和对象的一些注意事项五、其他语法:this六、其他语法:构造器七、其他语法:封装八、其他语法:实体JavaBean九、面向对象编程综合案例十、补充知识:成员变量、局部变量的区别小结 前言......
  • python的类方法--实例对象方法
    https://blog.csdn.net/weixin_60535956/article/details/127432990  方法区别若要修改实例的属性值,直接使用实例方法。若要修改类的属性值,直接使用类方法若是辅助功能(如打印菜单等),考虑使用静态方法,即可在不创建对象的前提下使用。注意:使用类名不能访问实例属性或实例......
  • 判断对象是否为空,包括里面的属性,如果里面的属性是空,也是空
    publicstaticbooleanisNoEmptyBean(Objectbean){if(null==bean){returnfalse;}for(Fieldfield:ReflectUtil.getFields(bean.getClass())){if(ModifierUtil.isStatic(field)){con......
  • JS中BOM事件,JS样式特效,表格对象和表单操作
    DOM事件1.DOM中的事件可以分为两类1.浏览器行为如:文档加载完成,图片加载完成2.用户行为如:输入框输入数据,点击按钮(2).常见的DOM事件onload浏览器已完成页面的加载支持事件的对象windowimageonchangeHTML元素改变onclick用户点击HTML元素o......
  • 数据库迁移系列】从MySQL到openGauss的数据库对象迁移实践
    数据库迁移系列】从MySQL到openGauss的数据库对象迁移实践原创酷哥[openGauss](javascript:void(0);)2022-11-0718:03发表于广东9月30日新发布的openGauss3.1.0版本,工具的全量迁移和增量迁移的性能不但有了全面提升,而且支持数据库对象视图、触发器、自定义函数、存储过程的......
  • 参考示例之“复制对象|拷贝对象|BeanUtils工具类学习”
    //设置需要拷贝的字段Set<String>targetSet=newHashSet<>();targetSet.addAll(Arrays.asList("totalRefund","actualAdvertisingCost","expensesOfTaxation"));//调用拷贝方法copyProperties(com......
  • 事务四大特性
    1.原子性:一个事务中所有操作要么全部成功要么全部失败。2.一致性:事务开始前后,数据库保持完整性3.隔离性:多个事务不会交叉执行4.持久性:事务处理结束后,对数据的修改是永久的......
  • 第十六节 面向对象进阶(多态&包&final&权限修饰符&代码块)
    今日内容多态包final权限修饰符代码块教学目标能够说出使用多态的前提条件理解多态的向上转型理解多态的向下转型能够知道多态的使用场景包的作用public和private权限修饰符的作用描述final修饰的类的特点描述final修饰的方法的特点......
  • 《深入理解Java虚拟机》读书笔记:HotSpot虚拟机对象探秘
    基于实用优先的原则,以常用的虚拟机HotSpot和常用的内存区域Java堆为例,深入探讨HotSpot虚拟机在Java堆中对象分配、布局和访问的全过程。以下是本节内容的脑图。 HotSpot虚拟机对象探秘脑图 一、对象的创建创建对象大致分为5步:1.检查类是否加载,没有加载先加载类2.分配内......
  • 关于Python的学习记录(二十一_对象的序列化和反序列化)
    JSON概述在Python中,我们可以将程序中的数据以JSON格式进行保存。JSON是“JavaScriptObjectNotation”的缩写,它本来是JavaScript语言中创建对象的一种字面量语法,现在已经被广泛的应用于跨语言跨平台的数据交换。使用JSON的原因非常简单,因为它结构紧凑而且是纯文本,任何操......