C++学习笔记之类和对象

本文详细探讨了C++中的类和对象,包括结构体在C和C++的区别,类的定义,构造函数,析构函数,初始化列表,explict关键字,赋值运算符重载,const成员函数,取地址运算符重载,静态成员和友元机制。特别强调了成员函数的存储位置,构造函数的作用,以及友元如何打破封装性。同时,还介绍了内部类的特性及其与外部类的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

结构体在C和C++的不同

1.在c++中,用结构体定义变量不需要加struct,而c中不行。

2.在C++中,可以定义空结构体,大小为1,而C中不行。

3.在C++中,可以在结构体声明中声明甚至实现函数,在C中只能放函数指针。

4.在C++中,成员函数直接可以访问本结构的成员变量而无需传入,在C中,函数和结构并无直接关联。

***成员函数不影响结构体的大小

因为成员函数是放在公共区域的,只是在这个结构体域中而已。 

类是一个特殊的结构体,只需要把上述结构体中的struct改成class,再加上public即可。

访问限定符:

public:正常访问       private:只能在类内部访问         protected:目前来说和private差别不大,但是主要差别体现在多态,继承的学习阶段 。

tip1:访问限定符只在编译阶段生效,编译好后,在运行阶段并没有限定。

tip2:结构体其实也能使用访问限定符,只是一般不去使用,因为它是用来兼容C结构体的。

tip3:结构体中默认是public,而类中默认是private。

注意点:

1.首先出现无穷递归/无穷调用的情况是在拷贝构造时候,拷贝构造的参数只有一个且必须使用引用传参,如果不使用引用传参则会出现无穷递归。

2.默认拷贝构造是浅拷贝,自己写的拷贝构造是深拷贝,若在牵扯到动态内存分配时候,自己不写拷贝构造函数,则会出现程序崩溃的情况,因为第二次析构的时候会引发错误。

3.在赋值运算符重载的时候bool operator=(const Date &d)假设是一个date类,那么我们可以理解为对=的赋值运算符重载,使用bool当然也可以,但是使用bool或者void 不可以多次赋值,例如d2=d1=d;但是若使用Date& operator=(const Date &d )则可以连续赋值。

构造函数

  1. 它是一个特殊的成员函数,它不存在返回值,名字和类名相同,在实例化对象的时候自动调用。
  2. 系统会自动提供一个默认的构造函数,如果自己实现了构造函数,则系统不再提供默认的构造函数。
  3. 构造函数可以存在参数,它与其它的构造函数是以函数重载的方式共同存在的。
  4. 拷贝构造函数指的是参数为本类其他对象的引用的构造函数,它在给对象初始化成本类其他对象时调用。系统会自动提供一个拷贝构造函数。

析构函数

  1. 析构函数是当一个栈被销毁前调用的,在C++中,当一个函数栈被销毁前,会调用栈中每一个函数的析构函数。 
  2. 析构函数不存在参数也不存在返回值,它的名字是类名前加波浪线。
  3. 系统会自动提供一个什么都不做的析构函数。

浅拷贝:直接复制内存。

深拷贝:当成员中有指向堆的指针,就必须重新给该指针分配空间,然后将目标对象指针所指的空间的内容拷贝到新分配的空间。(如果不这样做,会导致两个指针指向同一片空间,从而在析构中多次释放。

初始化列表

1.狭义初始化

在定义变量的时候直接进行初始化的行为叫做狭义初始化。 例如 int a = 3;

2.广义初始化

第一次给变量赋值叫做初始化的情况叫做广义初始化。

int a;

……//跟a无关的代码

a=3; 

初始化列表相当于狭义初始化,而构造函数内部相当于广义初始化。

所以初始化列表可以解决一些只能用狭义初始化进行初始化的变量,例如:const 变量              引用        没有无参构造的类的对象

explict

explict:阻止单参构造的不规范调用

单参数的构造函数:可以用=直接调用,例如:

假设CT类中有一个单参数的构造函数,参数类型为int或int相关类型,那么,"CT a = 3;"这种写法就是被允许的,但是这种写法十分别扭,看上去好像直接把3赋给了a,为了避免这种写法,可以在构造函数加explict,使得这样的写法变得无效。

赋值运算符重载

运算符重载:

将运算符看成函数,把它的几目当成参数,通过参数的类型识别出对应的操作方法,相当于函数重载。

运算符重载有指定的规则,规则根据运算符来制定。

类会自动提供一个赋值运算符的重载,执行的是浅拷贝,跟拷贝构造相同。

const成员函数 

const加在成员函数的末尾,代表这个函数的this是const修饰的。

如果一个对象是const对象,那么它不能调用非const的成员函数。

取地址运算符重载 

类会自动提供两个取地址运算符重载,一个是针对普通对象的,一个是针对const对象的。

静态成员 

静态成员跟类走不跟对象走,类在他在,而一般成员是对象在他才在。所以静态成员可以通过类名直接调用,而普通成员必须通过对象调用。

1.静态成员变量

1.所有对象共享,无论谁改了,所有的一起改。

2.存储在全局区,不占用类的空间,所以取sizeof的时候不算在内。

3.不需要对象,可以直接用类名::调用

4.赋初值只能在类外,赋值时不加static,用"类型 类名::变量名 = n"直接赋值

2.静态成员函数

只能直接访问静态成员变量,无法访问其它的普通成员,因为它没有this指针。 

友元 

友元分为友元函数和友元类。

友元提供了一种突破封装的方式,但是会增加耦合度,破坏了封装,所以友元不宜多用。

C++是一种面向对象的语言,具有封装,多态,继承三大特性 ,在类中,只有类的成员函数才可以访问类的私有成员,非成员函数只能访问类的公有成员,为了使类的非成员函数访问类的成员,唯一的做法就是将成员定义为public,但这样做会破坏信息隐藏的特性。基于以上原因,引入友元函数解决。友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。所以不建议使用。

友元函数

  • 必须在类的说明中说明友元函数,说明时以关键字friend开头,后跟友元函数的函数原型,友元函数的说明可以出现在类的任何地方,包括private和public部分。

  • 友元不是类的成员,不受类的声明区域public、private和protected的影响
  • 友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
  • 友元函数不是类的成员函数,所以友元函数的实现与普通函数一样。在实现时不用“::”指示属于哪个类,只有成员函数才使用“::”作用域符号。

  • 友元函数不能直接访问类的成员,只能访问对象成员

  • 我们试想一下,定义友元的目的是在不破坏隐藏(类的数据成员是private)的前提下,定义一个非成员函数访问私有数据成员。类的成员函数能“cout<< a<< endl;”的原因是有this指针。既然是私有数据成员,若要直接访问类的成员,且类的非静态成员必须与特定对象相对,所以必须通过类的对象访问类的私有数据成员。
    友元函数可以访问对象的私有成员,但普通函数不行。

  • 调用友元函数时,在实际参数中需要指出要访问的对象。

  • 类与类之间的友元关系不能被继承。(友元不属于类的成员函数)

  • 友元一般定义在类的外部,但需要在类体内进行声明,为了与该类的成员函数加以区分,在说明时前面加以关键字friend。友元函数不是成员函数,但它可以访问类的私有成员。友元的作用在于提高程序的运行效率,但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。

  • 对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,从而影响了程序的运行效率。

友元类

 友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员

  • 友元关系是单向的,不具有交换性
  • 友元关系不能传递。 B是A的友元,C是B的友元,则不能说明C是A的友元

内部类

内部类是指一个类定义在另一个类的内部。这个内部类就叫做内部类。此时内部类是一个独立的类,不属于外部类,更不能通过外部类的对象去访问内部类。

内部类就是外部类的友元类,但是外部类不是内部类的友元。

特性:

  • 内部类定义在外部类的public,protected,private都是可以的。
  • 内部类可以直接访问外部类中的static,枚举成员,不需要外部类的对象/类名
  • sizeof(外部类)=外部类,和内部类没有任何关系。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
class A
{
public:
  class B
  {
  public:
    void foo(const A& a)
    {
      cout<<k<<endl;
      cout<<a.h<<endl;
    }
  };
private:
  static int k;
  int h;
};
int A::k=1;
int main()
{
  A::B b;
  b.foo(A());
  return 0;
}

 注意写的时候的一些规范,尤其是静态成员的初始化,以及内部类在主函数的调用等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值