面向对象程序(C++)设计基础

news2024/12/23 3:15:13

一、类&对象

C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,通常被称为用户定义的类型。类提供了对象的蓝图,所以基本上,对象是根据类来创建的。声明类的对象,就像声明基本类型的变量一样。下面是一些针对类这一概念的知识记忆点📃。

  • 类的概念,首先是,数据的算法(操作)结合,构成一个不可分割的整体(对象)。其次,在这个整体中一些成员是保护的,他们被有效的屏蔽,以防外界的干扰和误操作。另一些成员是公共的,他们作为接口,提供给外界使用。

  • 一个类的所有对象调用的成员函数都来自于同一代码段,在调用成员函数的时候,其实传递了相应对象的指针。类的作用域是指类定义和相应成员函数定义的范围。类型名与非类型名在同一作用域之间可以重名。

  • 一个类的默认访问控制符为private。private和Product在访问控制的时候是一样的。

class Line// 类名
{
   public: //访问修饰符
      void setLength( double len );
      double getLength( void );//变量
      Line(double len);  // 这是构造函数
 
   private:
      double length;//方法
};
 
// 成员函数定义,包括构造函数
Line::Line( double len)
{
    cout << "Object is being created, length = " << len << endl;
    length = len;
}
 
void Line::setLength( double len )
{
    length = len;
}
 
double Line::getLength( void )
{
    return length;
}
// 程序的主函数
int main( )
{
   Line line;/声明Line类的对象line
 
   // 设置长度
   line.setLength(6.0); 
   cout << "Length of line : " << line.getLength() <<endl;
 
   return 0;
}

二、构造&析构函数

类的构造函数与析构函数是类的一种特殊的成员函数,每次创建类的新对象时执行构造函数,每个删除所建立的对象时执行析构函数。下面是一些笔者在学习此知识点时的一些笔记。📋

  • 析构函数也是特殊的类成员函数,它没有返回类型,没有参数,不能随意调用,也没有重载,只是在类对象生命周期结束的时候,由系统自动调用。析构函数以调用函数相反的顺序被调用。构造函数能够给参数配置默认值,如果为类定义了一个带参数的构造函数,还想要无参的构造函数,则必须自己定义。

  • 为解决成员变量初始值的问题(包括成员变量为对象),可在构造函数后添加:运算符,并可以用分开。()表示初始化的参量。在包含对象成员的类对象创建的时候,需要对象成员的创建,相应的调用对象成员的构造函数。然而,构造对象成员的顺序要看类中的声明顺序,而不是看构造函数说明中冒号后面成员初始化的顺序。

C::C( double a, double b, double c): X(a), Y(b), Z(c)
{
  ....
}

我们从更深层次的数据存储以及对象间相互赋值的底层原理,了解一下堆与拷贝构造函数的相关概念如下:👀

  • 全局变量,静态数据,常量存放在全局数据区,所有类成员函数和非成员函数存放在代码区,为运行函数而分配的局部变量,函数参数,返回数据,返回地址等存放在栈区,余下的空间都被作为堆区。

  • new是为一个固定的数据类型在堆内申请一段空间,包含数据的构造这个过程。从堆上分配对象数组,只能调用默认的构造函数,不能调用其他任何构造函数。在默认拷贝构造函数中,拷贝的策略是逐个成员依次拷贝。拷贝构造函数的形参为类型的引用。如果你的类需要一个析构函数来析构资源,则它也需要一个拷贝构造函数(深拷贝与浅拷贝的区别是在拷贝构造函数是否申请了资源)。

  • 在返回值为对象的时候,会产生临时对象,临时对象在整个创建他们的外部表达式范围内有效。

三、静态成员与友元

我们可以使用 static 关键字来把类成员定义为静态成员。类定义中函数原型前使用关键字 friend来声明为一个类的友元函数。下面是一些针对静态成员以及友元的概念详解。🔖

  • 静态成员只与类相联系。静态数据成员在类声明外分配空间和初始化。一个静态成员函数不与任何对象联系,故不能对非静态成员进行默认访问。(静态成员函数和非静态成员函数的本质区别是静态成员函数没有this指针)。

  • 友元是独立的函数,不是类的成员函数。友元的添加是为了提高效率,防止成员函数的反复调用。友元函数同时在两个类中生命,即可以访问两个类中的内容。一个类的成员函数,可以是另一个类的友元。整个类可以使另一个类的友元。友类的每个成员函数都可访问另一个类中的保护或私有数据成员。

四、继承

面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。继承代表了一种包含关系。例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物,等等。

4.1继承基本概念

  • 多态性:函数接收的形参是基类,而实参如果是父类,则还是调用父类的重载函数(函数声明一模一样)。这样就导致函数内调用的函数会发生多态,用迟后联编或者叫滞后联编来确定到底用哪个函数。含有父类的子类,布局上This指针先指向父类数据部分,后指向子类数据部分。

  • 若语言不能支持多态,则不能称之为面向对象的。多态性增加了一些数据存储和执行指令的代价。有一种例外,如果基类中的虚函数返回一个基类指针或返回一个基类的引用,子类中的虚函数返回一个子类的指针或者子类的引用,则C++将其视为同名虚函数而进行迟后联编。

  • 一个类中的将所有的成员函数都尽可能地设置为虚函数对编程固然方便,JAVA语言中正是这样做的,但是会增加一些时空上的开销。对于C++来说,在对性能上有偏激追求的编程中,只选择设置个别成员函数为虚函数。

  • 只有类的成员函数才能说明为虚函数,静态成员函数不能是虚函数(this指针加虚函数列表实现多态),内联函数不能为虚函数。构造函数不能是虚函数,析构函数可以是虚函数,并且通常声明为虚函数。

  • 多态性虽然可以解决类的冗余,但是为了解决类的冗余而可以制造包含关系,将使问题往不可控制的方向发展。类的分解才是更好解决冗余的方法,将两个冗余的类根据冗余部分再抽象一个类,再让这两个冗余的类继承这个抽象出来的类。

  • 具有纯虚函数的类为抽象类,其并不能构造一个具体的类。纯虚函数是在积累中为子类保留一个位置,以便子类用自己的实在函数定义来覆盖之,如果在基类中没有保留位置,则就没有覆盖。

  • 保护的访问权限对于派生类来说是共有的,而对于其他对象来说是私有的,派生类也不能访问基类中私有的数据成员和成员函数。

4.2多重继承:

多重继承指的是一个类可以同时继承多个 类 ,比如A类继承自B类和C类,这就是多重继承。下面是对继承更多相关概念的一些详解。

  • 在多重继承的时候,出现名称的冲突,需要说明基类:对象名.基类名.成员函数(或者成员变量)

  • 虚拟继承的虚拟和虚拟函数的虚拟没有任何关系,虚拟继承的作用就是如果还没有基类,则加入一个基类的拷贝,否则就用有的那个基类。任何虚拟函数基类的构造函数按照他们被继承的顺序构造。任何非虚拟基类的构造函数按照他们被继承的顺序构造。任何成员对象的构造函数按照他们声明的顺序调用。类自己的构造函数。

  • 在继承的关系中,基类的private成员不但对应用程序隐藏,甚至对派生类也隐藏。而基类的保护成员则只对应用程序隐藏,而对派生类毫不隐瞒。一个私有的或保护的派生类不是子类,程序不能接受其变为子类引用去传递给函数形参。.在无继承的类中,protected和private控制符是没有区别的。在继承中,基类的private对所有的外界都屏蔽(包括自己的派生类),基类的protected控制符对应用程序是屏蔽的,但对其派生类是可访问的。

下面是针对继承概念的一个简单C++实现:

#include <iostream>
 
using namespace std;
 
// 基类
class Shape 
{
   public:
      void setWidth(int w)
      {
         width = w;
      }
      void setHeight(int h)
      {
         height = h;
      }
   protected:
      int width;
      int height;
};
 
// 派生类
class Rectangle: public Shape
{
   public:
      int getArea()
      { 
         return (width * height); 
      }
};
 
int main(void)
{
   Rectangle Rect;
 
   Rect.setWidth(5);
   Rect.setHeight(7);
 
   // 输出对象的面积
   cout << "Total area: " << Rect.getArea() << endl;
 
   return 0;
}

五、运算符重载:

您可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。下面的代码将针对Box加法运算符进行了重载,用于把两个 Box 对象相加,返回最终的 Box 对象。

// 重载 + 运算符,用于把两个 Box 对象相加
      Box operator+(const Box& b)
      {
         Box box;
         box.length = this->length + b.length;
         box.breadth = this->breadth + b.breadth;
         box.height = this->height + b.height;
         return box;
      }

下面是一些与运算符重载的相关概念详解:📑

  • 运算符是函数,除了运算顺序和优先级不能修改之外,参数和返回值类型是可以重新说明的,即可以重载,重载的形式是,返回类型 operator 运算符号(参数说明)。运算符重载作为成员函数在声明和第一时,形式上少了一个参数,这是由于C++对所有的成员函数隐藏了第一个参数this。return *this 当返回值为引用的时候。

  • 后增量返回的是原有对象值的临时对象。C++约定,在增量运算符定义中,放上一个整数形参,就是后增量运算符。前增量运算符返回引用,后增量运算符返回值。

  • 转换运算符将对象转换成类型名规定的类型。operator double(){};寻找的次序:1.寻找成员函数的+运算符;2寻找非成员函数的+运算符。3.由于存在内部运算符operator +(double,double);所以假定匹配其程序中的算法。4.寻找能将实参(RMB对象)转化为double型的转换运算符operator double()。

  • 转换运算符与转换构造函数互逆。例如类名(double)转换构造函数将double转换为RMB,而RMB::operator double()将RMB转换成double。转换运算符没有返回值。拷贝构造函数和赋值运算符,区别在类的对象是否已经存在。赋值运算符符实现之前,释放已有对象所占用的资源。

六、I/O流

C++的IO流,特指以流的方式进行输入输出的ISO/ANSI标准C++库的输入输出类库,也就是专门负责处理IO操作的一套系统。 任何需要传递的数据,都要经过这套系统的处理 。下面是我对C++的I/O流的一些个人理解。💾

  • 写到cerr上的信息是不能被重定向的。

  • .I/O标准流类:头文件为iostream.h;C++的名字为cin,cout,cerr,clog。文件流类:头文件fstream.h,ofstream,ifstream,fstream。串流类:头文件strstrea.h。ostrstream,istrstream,strstream。

  • 控制符,用流对象的成员函数控制输出的格式,用控制符。流成员函数的优点是可以返回以前的设置,便于恢复设置。

5.控制符,用流对象的成员函数控制输出的格式,用控制符。流成员函数的优点是可以返回以前的设置,便于恢复设置。cin遇到空格等分隔符就会为一个接收单元,getline为cin的成员函数,能够读取已整行的文本。cin.get不跳过任何空白字符。

6.cin遇到空格等分隔符就会为一个接收单元,getline为cin的成员函数,能够读取已整行的文本。cin.get不跳过任何空白字符。

七、模板:

模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。每个容器都有一个单一的定义,比如 向量,我们可以定义许多不同类型的向量,比如 vector <int> 或 vector <string>。我们可以使用模板来定义函数和类,接下来是我记录的一些个人理解。🏢

  • 用函数模板可以将许多重载函数简单的归为一个。要是重载函数和模板函数同时存在,则先进行重载函数的匹配,然后再寻求模板的匹配。

  • 模板类:template <class T> class 类名{这里边就用T来表示这个数据类型};之后的里边成员函数的实现:template <class T> 返回值 类名<T>::函数名(形参)。

  • 使用类的模板方法:(1)在程序开始的头文件说明模板的定义。(2)在适当的地方创建一个模板类的实例,编译发现正在创建一个类模板对象的时候,便会创建该模板类的定义,同时,创建对应的对象实体。(3)有了对象名,以后的使用就和通常一样,但是要记住,你规定了什么类型的模板类,在使用成员函数的时候,所赋的实参也要对应该类型。

下面的实例定义了类 Stack<>,并实现了泛型方法来对元素进行入栈出栈操作:

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
 
using namespace std;
 
template <class T>
class Stack { 
  private: 
    vector<T> elems;     // 元素 
 
  public: 
    void push(T const&);  // 入栈
    void pop();               // 出栈
    T top() const;            // 返回栈顶元素
    bool empty() const{       // 如果为空则返回真。
        return elems.empty(); 
    } 
}; 
 
template <class T>
void Stack<T>::push (T const& elem) 
{ 
    // 追加传入元素的副本
    elems.push_back(elem);    
} 
 
template <class T>
void Stack<T>::pop () 
{ 
    if (elems.empty()) { 
        throw out_of_range("Stack<>::pop(): empty stack"); 
    }
    // 删除最后一个元素
    elems.pop_back();         
} 
 
template <class T>
T Stack<T>::top () const 
{ 
    if (elems.empty()) { 
        throw out_of_range("Stack<>::top(): empty stack"); 
    }
    // 返回最后一个元素的副本 
    return elems.back();      
} 
 
int main() 
{ 
    try { 
        Stack<int>         intStack;  // int 类型的栈 
        Stack<string> stringStack;    // string 类型的栈 
 
        // 操作 int 类型的栈 
        intStack.push(7); 
        cout << intStack.top() <<endl; 
 
        // 操作 string 类型的栈 
        stringStack.push("hello"); 
        cout << stringStack.top() << std::endl; 
        stringStack.pop(); 
        stringStack.pop(); 
    } 
    catch (exception const& ex) { 
        cerr << "Exception: " << ex.what() <<endl; 
        return -1;
    } 
}

八、异常

异常是程序在执行期间产生的问题。C++ 异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字:try、catch、throw。当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。try 块中放置可能抛出异常的代码,catch 关键字用于捕获异常。下面是笔者在学习这段内容时候的一些笔记:💊

  • 错误一种为编译错误,另一种为运行中发现的错误,它分为不可预测的逻辑错误和可以预测的运行异常。在c++中,异常是指从发生问题的代码区域传递到处理问题的代码区域的一个对象。

  • .C++只理会受监控过程之异常,在try块之后必须紧跟一个或多个catch()语句,目的是对发生的异常进行处理。catch()括号中的声明只能容纳一个形参,当类型与抛掷异常的类型匹配的时候,该catch()块便称捕获了一个异常而转到其块中进行异常处理。

  • 异常的规则:(1)任意数量的catch分程序立即出现在try分程序之后,在try分程序出现之前,不能出现这些catch程序块。(2)跟在Catch之后圆括号中必须包含有数据类型,捕获是利用数据类型匹配实现的。(3)如果一个函数抛一个异常,但是在通往异常处理函数的调用链中找不到与之匹配的catch,则该程序调用一个abort()函数终止调用。这个参数必须是严格匹配(4.)如果catch分程序执行完毕,则跟随最后catch分程序的代码(如果有的话)就被执行。

  • 一个对象不含数据成员,则没有必要给捕获对象一个名字。抛掷的异常如果在try内,正常匹配catch语句,如果不在,则向上游的catch语句去匹配。如果上游也没有,则C++将执行默认的异常处理函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/340629.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面试题(二十二)消息队列与搜索引擎

2. 消息队列 2.1 MQ有什么用&#xff1f; 参考答案 消息队列有很多使用场景&#xff0c;比较常见的有3个&#xff1a;解耦、异步、削峰。 解耦&#xff1a;传统的软件开发模式&#xff0c;各个模块之间相互调用&#xff0c;数据共享&#xff0c;每个模块都要时刻关注其他模…

Grafana 系列文章(十五):Exemplars

Exemplars 简介 Exemplar 是用一个特定的 trace&#xff0c;代表在给定时间间隔内的度量。Metrics 擅长给你一个系统的综合视图&#xff0c;而 traces 给你一个单一请求的细粒度视图&#xff1b;Exemplar 是连接这两者的一种方式。 假设你的公司网站正经历着流量的激增。虽然…

ansible的模块详解

ansible 的概述 什么是ansible Ansible是一款为类Unix系统开发的自由开源的配置和自动化工具。 它用Python写成&#xff0c;类似于saltstack和Puppet&#xff0c;但是有一个不同和优点是我们不需要在节点中安装任何客户端。 它使用SSH来和节点进行通信。Ansible基于 Python…

Redux 源码分析

Redux 目录结构 redux ├─ .babelrc.js ├─ .editorconfig ├─ .gitignore …

列线图工具_Nomogram

定义 列线图是一种相对传统的分析方法&#xff0c;用于展示自变量和因变量的线性关系&#xff0c;及其特征的重要程度。 现在用SHAP&#xff0c;和机器学习库中的 Feature importance 工具可以实现类似甚至更好效果。不过很多传统的研究领域比较认这种方法。 列线图工具建立在…

什么是相机标定

1. 相机标定的定义及作用 相机标定是指借助标定板来计算单个或多个相机的内参、外参和镜头畸变参数。 作用&#xff1a; 将畸变的图像恢复为正常的图像&#xff0c;为后续进行拼接、SLAM等奠定基础。 多相机标定可以将所有相机输出变换到同一个坐标系。 相机标定是三维视觉…

适用于 Windows 11/10/8/7 的 10 大数据恢复软件分享

适用于 Windows 11/10/8/7 的 最佳数据恢复软件综述。选择首选的专业数据/文件恢复软件&#xff0c;轻松恢复丢失的数据或删除的照片、视频等文件、SSD、外接硬盘、USB、SD卡等存储设备中的文件等。流行的sh流行的数据恢复软件也包括在内。 10 大数据恢复软件分享 为了帮助您恢…

美赛Day2

3 熵权法 相对客观的权重计算方法&#xff08;层次分析法都是自己瞎填&#xff09; 3.1 原理 指标的变异程度越小&#xff0c;反应的信息越少&#xff0c;对应的权值越低。 一个事件的信息量&#xff1a;I(x) -ln(p(x)) 信息熵&#xff1a;对X可能发生的所有情况的信息量的…

仿真与测试:通过Signal Builder模块生成输入信号

本文研究通过Signal Builder模块生成输入信号的方法。 文章目录1 生成输入信号2 仿真过程2.1 搭建被测模型2.2 搭建Signal Builder输入模块2.3 配置仿真log及仿真3 总结1 生成输入信号 在汽车的电控软件开发中&#xff0c;经常会在Simulink模型内部进行单元测试。单元测试的本…

FlexRay™ 协议控制器 (E-Ray)-04

网络管理 累积的网络管理 (NM) 向量位于网络管理寄存器 1 到网络管理寄存器 3 (NMVx (x = 1-3)) 中。【The accrued Network Management (NM) vector is located in the Network Management Register 1 to Network Management Register 3 (NMVx (x = 1-3)).】 网络管理向量 x…

『前端必备』本地数据接口—json-server

文章目录前言一、json-server简介二、起步三、使用步骤前言 Ajax 是前端必学的一个知识点&#xff0c;但刚接触 Ajax 的同学可能会因为没接口测试而烦恼。本文 入门篇 会花你10分钟解决 没接口测试 这个烦恼&#xff0c;而且不需要你具备后端知识。 一、json-server简介 json…

一个测试人员,在现阶段的环境下如何在测试行业发展和自我价值。

前言周末和几个测试圈子里的大佬饭局上聊了一些职场和测试职业发展相关的话题&#xff0c;我将聊天的内容做了整理和阐述。。朋友圈有测试同学对这篇文章提了比较深刻的建议&#xff0c;下面是他的评价和建议&#xff1a;评价&#xff1a;据说是大佬饭桌总结&#xff0c;有两点…

【论文精读】Deep Residual Learning for Image Recognition

1 Degradation Problem&#x1f4a6; 深度卷积神经网络在图像分类方面取得了一系列突破。深度网络自然地将低/中/高级特征和分类器以端到端的多层方式集成在一起&#xff0c;特征的“层次”可以通过堆叠层数(深度)来丰富。最近的研究揭示了网络深度是至关重要的&#xff0c;在具…

Netty零拷贝机制

Netty零拷贝机制一&#xff1a;用户空间与内核空间二&#xff1a;传统IO流程三&#xff1a;零拷贝常见的实现方式1. mmap write2. sendfile四&#xff1a;Java中零拷贝五&#xff1a;Netty 中如何实现零拷贝1. CompositeByteBuf 实现零拷贝2. wrap 实现零拷贝3. slice 实现零拷…

Pytorch 混合精度训练 (Automatically Mixed Precision, AMP)

Contents混合精度训练 (Mixed Precision Training)单精度浮点数 (FP32) 和半精度浮点数 (FP16)为什么要用 FP16为什么只用 FP16 会有问题解决方案损失缩放 (Loss Scaling)FP32 权重备份黑名单Tensor CoreNVIDIA apex 库代码解读opt-level (o1, o2, o3, o4)apex 的 o1 实现apex …

Docker安全

容器的安全性问题的根源在于容器和宿主机共享内核。如果容器里的应用导致Linux内核崩溃&#xff0c;那么整个系统可能都会崩溃。 与虚拟机是不同的&#xff0c;虚拟机并没有与主机共享内核&#xff0c;虚拟机崩溃一般不会导致宿主机崩溃 一、Docker 容器与虚拟机的区别 1、隔…

Redis配置哨兵模式

Redis配置哨兵模式 ​ ​ 主从复制模式&#xff0c;它是属于 Redis 多机运行的基础&#xff0c;但这种模式本身存在一个致命的问题&#xff0c;当主节点奔溃之后&#xff0c;需要人工干预才能恢复 Redis 的正常使用。 我们需要一个自动的工具——Redis Sentinel&#xff08;…

Win11浏览器无法上网,秒杀网上99.9%教程—亲测完胜

前言 例如&#xff1a;网上的教程 列如&#xff1a; 关闭代理服务器、QQ微信可以登录&#xff0c;但浏览器无法上网、Win11、Win10无法上网、重启网络、重启电脑、去掉代理服务器等等。 一系列教程&#xff0c;要多鸡肋就多鸡肋。 我是用我2020年在CSDN上发布的第一篇文章&…

自动驾驶规划 - Apollo Lattice Planner算法【1】

文章目录Lattice Planner简介Lattice Planner 算法思路1. 离散化参考线的点2. 在参考线上计算匹配点3. 根据匹配点&#xff0c;计算Frenet坐标系的S-L值4. parse the decision and get the planning target5. 生成横纵向采样路径6. 轨迹cost值计算&#xff0c;进行碰撞检测7. 优…

Fluent Python 笔记 第 8 章 对象引用、可变性和垃圾回收

本章先以一个比喻说明 Python 的变量&#xff1a;变量是标注&#xff0c;而不是盒子。如果你不知道引用式变量是什么&#xff0c;可以像这样对别人解释别名。 然后&#xff0c;本章讨论对象标识、值和别名等概念。随后&#xff0c;本章会揭露元组的一个神奇特性&#xff1a;元…