【C++技能树】再也不怕没有对象了 --初识类

简介: 我们先来看看C语言解决一个问题的过程。

Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法…感兴趣就关注我吧!你定不会失望。


36603d2e4ee04064a06d32db1bfdf360.png


0. 初识类


我们先来看看C语言解决一个问题的过程。


假设有以下这个场景:你需要把大象放进冰箱,你需要做哪几步?


1.打开冰箱门

2.拿起大象

3.把大象放进冰箱

4.关上冰箱门


这是用C语言解决一个问题的过程,那么来看下C++是怎么解决这个问题的.


在C++当中,把每一个用到的对象抽离了出来,例如这里的:你,冰箱,大象都会被归类为一个个对象,而你们会有自己的属性,也就是自己的动作,而此时你就不需要去关注,人是怎么把大象拿起,怎么把大象放进冰箱,你只需要关心一个个对象之间的逻辑就可以了.


59fc3e1dd703468c8dede757148b252c.png


1.类的引入


先来看看我们之前最熟悉的C语言中的Struct在C++中他被升级成了类.


struct cdate{
  int _date;
  int _month;
  int _year;
};


这是在c语言中我们就会使用的方法,他被升级成类之后有了什么变化呢?


在一个结构体里可以定义函数了:


#include<iostream>
using namespace std;
struct cdate{
  int _date;
  int _month;
  int _year;
  int max(int a,int b)
  {
    return a>b?a:b;
  }
};
int main()
{
  cdate c;
  cout<<c.max(5,3);
}


这在c中是不可以的,不信的uu们可以去试试(要将文件名后缀改成C哦,不然编译器会以C++的标准来运行)


定义一个Struct的时候再也不用写Struct了.


这个直接看上面的cdate即可.


但在C++中更喜欢用Class来替换上面的struct,所以我们一般将代码写成这样:(关于public是什么意思接下来会解释,这里直接写就好啦)


#include<iostream>
using namespace std;
class cdate{
public:
  int _date;
  int _month;
  int _year;
  int max(int a,int b)
  {
    return a>b?a:b;
  }
};
int main()
{
  cdate c;
  cout<<c.max(5,3);
}


这就是一个类的大概状态啦,接下来我们将更详细的解释一下类的各部分.

2.类的定义


class classname
{
  //类体
};


class为定义类的关键字,classname为类的名字,{}中为类的主体,与结构体相同,结束时也需要加上一个;


所以类的组成由两个部分组成:类体与类名

类体中的内容称为类的成员:


1. 类的变量称为类的属性或成员变量
1. 类中的函数称为类的方法或者成员函数


类的两种定义方式:


类定义了一个新的作用域,仅能在这个作用域里访问其private成员


与C相同定义一个函数的时候也可以采用声明与定义放在同一个地方的方式:


class max{
public:
  int max(int a,int b)
  {
    return a>b?a:b;
  }
};


例如这里的max函数,但更推荐采用下面这种方式,将函数声明放在类中,定义写在这个类的外面(也可以解释为将类的声明放在头文件当中,类的具体定义放到源文件当中,这样做的好处和c一样),但注意,这样写要在定义处加上一个**类作用声明符**:


class cdate{
public:
  int max(int a,int b);
};
int cdate::max(int a,int b)
{
  return a>b?a:b;
}


其中**cdate:😗*为类作用声明符.


成员变量的命名规范:


看看这个函数:


class student {
public:
  void inname(int score)
  {
    score = score;
  }
  void print()
  {
    cout << score;
  }
private:
  int score = 0;
};
int main()
{
  student s1;
  s1.inname(80);
  s1.print();//80
}


这里定义了一个简单的student对象,对他的分数进行输入输出(一样private马上就会讲是什么东西),我们观察inname中的这段代码:


score=score


这里执行的结果本意是想要将外部传进的参数放进这个s1的score当中,但似乎外部的参数与内部的属性相互重合了.所以我们一般将内部属性命名添加一个_,来表示是内部的属性(不同的工作环境命名规范不同,但要有这么个意识)


所以这段代码应该写成这样:


class student{
public:
  void inname(int score)
  {
    _score=score;
  }
  string name;
  void print()
  {
    cout<<_score;
  }
private:
  int _score=0;
};
int main()
{
  student s1;
  s1.inname(80);
  s1.print();//80
}


3.类的访问限定符与封装


这里介绍以下上文提到的private,public,protected.


b5b91171237146368966e2d62c6fc044.png


1.在类中访问权限作用域一直到下一个访问权限符出现为止

2.public修饰的成员在类外可以直接被访问


3.private与protected(他们虽然有一些细微的差别,但先认为他们是一样的)修饰的成员在类外无法被访问,通常通过调用Public里的对应函数来进行访问.


面试题:C++中的struct与class的差别是什么


C++需要兼容C语言,所以**C++中的struct可以当成结构体用,同时也可以用来定义类.**区别是:struct的默认权限是public(为了兼容C语言)而class的默认权限是private


这三个限定符的作用是什么?


看看你面前的计算机,平常需要将其开机要做的就是按下面前的电源键,而不需要关心他的电路是如何运作的.这就是将电路进行了**private**,而将开机按钮的权限为 public,你可以直接通过这个public的方法去让他开机.也就是作为一个用户仅需要关注他能实现的功能而不需要去关注他的实现细节


在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用


4.类的实例化


下面是一个类的定义(也可以叫模板,这里的模板与C++中的模板没有任何关系)


class student{
public:
  void inname(int score)
  {
    _score=score;
  }
  string name;
  void print()
  {
    cout<<_score;
  }
private:
  int _score=0;
};


可以把这个模板看作一个设计图,它本身不占空间,只是设计出了这个房子的构成.但你用这个设计图去造出一个个房子(实例化一个个对象).他就占空间了.


class student{
public:
  void inname(int score)
  {
    _score=score;
  }
  string name;
  void print()
  {
    cout<<_score;
  }
private:
  int _score=0;
};
int main()
{
  student s1;
  s1.inname(80);
  s1.print();//80
}


类的空间计算


还是那个设计图的例子,我们可以将一个类的函数比作这个小区的各种公共设施,每一个家庭都要用到电梯,但我需要为每一个家庭都装上一个电梯嘛?显然是不需要的,也就是说一个类的函数是公用的,他们被存储在了公共代码区.而每一个家庭里的设施虽然都是从模板里设计出来的,但是会有一些差异,所以我们需要保存每一个对象的属性.


所以类的存储模型就是这样:


7e0a8b638c1a4ccda74b5f239d0d7a48.png


所以计算一个对象的所占内存大小的时候仅需计算成员属性的内存大小(其符合结构体内存对齐的规则)


class student{
public:
  void inname(int score)
  {
    _score=score;
  }
  void print()
  {
    cout<<_score;
  }
private:
  int _score=0;
  char _name;
};
int main()
{
  student s1;
  cout<<sizeof(s1);//8
}


目录
相关文章
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
472 12
|
10月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
254 0
|
10月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
401 0
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。
|
存储 编译器 C++
类和对象(上)(C++)
本篇内容主要讲解了C++中类的相关知识,包括类的定义、实例化及this指针的作用。详细说明了类的定义格式、成员函数默认为inline、访问限定符(public、protected、private)的使用规则,以及class与struct的区别。同时分析了类实例化的概念,对象大小的计算规则和内存对齐原则。最后介绍了this指针的工作机制,解释了成员函数如何通过隐含的this指针区分不同对象的数据。这些知识点帮助我们更好地理解C++中类的封装性和对象的实现原理。
|
编译器 C++
类和对象(下)C++
本内容主要讲解C++中的初始化列表、类型转换、静态成员、友元、内部类、匿名对象及对象拷贝时的编译器优化。初始化列表用于成员变量定义初始化,尤其对引用、const及无默认构造函数的类类型变量至关重要。类型转换中,`explicit`可禁用隐式转换。静态成员属类而非对象,受访问限定符约束。内部类是独立类,可增强封装性。匿名对象生命周期短,常用于临时场景。编译器会优化对象拷贝以提高效率。最后,鼓励大家通过重复练习提升技能!
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
236 16
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
847 6