《C++高级编程》-软件工程

第二十四章 充分利用软件工程方法

24.2 软件生命周期模型

瀑布模型:规划-设计-实现-单元测试-子系统测试-整合测试-评估。上一步完成才开始下一步
生鱼片模型:以上步骤前后有重叠部分

螺旋类模型-风险驱动的开发过程,基本思想:出错也没关系,下一轮会修复这个问题。
发现阶段:构建需求,确定目标,替代方案,其他约束
评估阶段,考虑评估方案,分析风险,构建原型系统。朱忠此阶段的风险评估和解决。
开发阶段,期间任务由前两个阶段确定的风险决定。
分析阶段:信息工程下一个周期计划。

规划(主需求)-原型(可展示)- 构建实现高风险组件。三个步骤重复上述四个阶段
相当于允许迭代的瀑布模型

迭代时间范围太长成了瀑布模型。

敏捷开发注重客户需求的快速实现,而不是开发过程本身的高效。

24.3 软件工程方法论

24.3.1 UP

unified process——统一过程
迭代和增量的软件开发过程。根据项目的特定需求进行定址。分四个阶段:
起始阶段(inception)通常短暂。包括可行性研究,编写业务案例,决定内部开发还是外包,确定成本和时间线。
细化阶段(elaboration)把大多数需求记录,消除风险,验证系统架构。为验证架构,实现核心功能以验证它可以支撑整个系统
构建阶段(construction)在架构上完成全部需求
交付阶段(transition)交付并更具客户反馈,后续处理

P582 图24-6

24.3.2 RUP

rational unified process。rational统一过程。

24.3.3 Scrum

实现敏捷模型。定义了日常使用的方法。
是迭代过程,管理软件开发项目的手段。
每个迭代称为sprint周期,是scrum过程的核心部分。
sprint周期的长度在项目开始决定–通常2~4周。每个周期结束时,目标是有一个完全可用且经过测试的软件版本。它要是客户需求的一个子集。
因为需求易变,可以将每个周期的结果发给客户,反馈意见。

有三个角色
Product Owner,客户与其他人之间桥梁作用–根据客户描述编写产品要实现的具体功能。
Scrum Master,负责保持过程运行,可以是团队的一部分,但不是团队领导,scrum中团队自我管理。sm是团队的联络人,使成员专注于自己的任务,保证遵循scrum过程,组织日常scrum会议。
团队本身,负责开发,精简,不多于10人。

过程;
强制没人例会-daily scrum/standup。简短,回答三个问题:
自从上次daily scrum会议以来做了什么
本次会议后打算做什么
为达到目标面临什么问题,SM关注该部分,并尝试会议之后解决。
每个周期前有个计划会,讨论新周期内从需求总表上去除那部分功能来实现,分解成小任务,评估工作量,期间需求总表别乱改。
同时分todo,in progress,done,每个任务分类
之后review分析总结该周期内问题,同时给出可展示demo

P583

24.3.4 极限编程

Extreme Porgramming-XP
精细的反馈–提供与编码,规划和测试相关的4条指导原则。
结对编程:二人编写,一个写,一个审查
计划策略:版本计划与开发人员和客户相关,旨在确定未来的版本需求包括哪些要求;迭代计划仅与开发人员相关,规划开发人员的实际任务。功能被分解成不超过五天的任务。
不断测试:不断对负责的部分代码编写单元测试,它通常是一小块代码。可以在实现功能之前编写,如果测试时完成的,就应该知道什么时候代码才算完成,因为此时才能通过测试----TDD(test driven development,测试驱动开发)

持续的过程
倡导持续集成子系统,从而及时发现子系统之间的不匹配,必要时重构代码。
不断整合:频繁地整合代码进项目,通过测试暴露问题
必要时重构:重设计
构建小型发布:不要一次实现太多。最重要的功能才会进入发布版本,迫使确定哪些工程真正重要

寻求共识
为了共享代码
共同的编码标准:命名约定和缩进约定。如果有很强的个人风格,那么需要更好地定义编码标准。
共享代码:允许修改完成其他人负责的代码,每个人都熟悉其他人负责的部分。
简化设计:设计简单,能用的对象存储,满足当前需求,而不是包罗万象,最终成了STL。立足当下,修改是明天的事情。
有共同的隐喻(metaphor):对系统有高层次的看法。统一的词汇。

24.3.5 软件分流

software triage:快要GG的项目,啥都却的情况下,利用剩下的资源完成任务。保留核心,去掉非必要功能

第二十五章 编写高效的C++程序

第二十六章 测试

第二十七章 调试

错误日志工具 win上的实践报告API
boost.log
log4cpp

27.4.3 断言–运行时

<cassert>头文件定义了assert宏,接收一个布尔表达式,如果为false则打印一条错误信息并终止程序。—发生于灾难性错误

27.4.4 崩溃转储–更有价值

内存转储,是一个转储文件,崩溃时创建,包含:哪个线程在运行,所有线程的调用堆栈等。与平台相关的文档,或第三方库breakpad
建立符号服务器和源代码服务器。符号服务器用于存储软件发布二进制版本的调试符号,可以用于解释来自客户的崩溃转出。
源代码服务器储存代码的所有修订。

27.5 静态断言

static_assert编译时对断言求值。接收两个参:编译时求值的表达式和字符串。为false时将给出包含指定字符串的错误提示。
核实是否是64位编译器编译

static_assert(sizeof(void*) == 8, "Requires 64-bit compiliation");

32位则指针是4个字符,报错:
test.cpp(3): error C2338: Requires 64-bit compilation
C++17 ,字符串参数可选。此时出错,错误信息和编译器相关了。

结合trait
static_assert(is_base_of_v<Base1, T>);

当不同参数类型的base2调用base1的方法时,就会报错

第二十八章 使用设计技术和框架

28.1 容易忘记的语法

RAII

28.2.2 双分派

实际上是多分派的特例。多分派是根据两个或多个对象的运行时类型选择行为。在实践中,双分派可根据两个对象的运行时类型选择行为。
例如:
animal基类派生出其他类,都包含eat()和eatenby()方法,这样当调用eat()方法时,多态性确定调用哪一个动物类的eat()方法。调用eatenby()时,多态性再次确定要调用哪个类的方法版本,此时调用prey对象运行时类型的eatenby()

bool Bear::eat(const Animal& prey) cosnt
{
	return prey.eatenby(*this);
}

*this的运行时类型始终与编译时类型相同,这样编译器可为实参(这里是Bear)调用eatenby()的正确重载版本。

#include <iostream>

using namespace std;

// Forward declarations.
class Fish;
class Bear;
class TRex;

class Animal
{
public:
	virtual bool eats(const Animal& prey) const = 0;

	virtual bool eatenBy(const Bear&) const = 0;
	virtual bool eatenBy(const Fish&) const = 0;
	virtual bool eatenBy(const TRex&) const = 0;
};

class Bear : public Animal
{
public:
	bool eats(const Animal& prey) const override { return prey.eatenBy(*this); }

	bool eatenBy(const Bear&) const override { return false; }
	bool eatenBy(const Fish&) const override { return false; }
	bool eatenBy(const TRex&) const override { return true; }
};

class Fish : public Animal
{
public:
	bool eats(const Animal& prey) const override { return prey.eatenBy(*this); }

	bool eatenBy(const Bear&) const override { return true; }
	bool eatenBy(const Fish&) const override { return true; }
	bool eatenBy(const TRex&) const override { return true; }
};

class TRex : public Animal
{
public:
	bool eats(const Animal& prey) const override { return prey.eatenBy(*this); }

	bool eatenBy(const Bear&) const override { return false; }
	bool eatenBy(const Fish&) const override { return false; }
	bool eatenBy(const TRex&) const override { return true; }
};


int main()
{
	Fish myFish;
	Bear myBear;
	TRex myDino;
	
	cout << boolalpha
	cout << "Fish eats bear? " << myFish.eats(myBear) << endl;
	cout << "Fish eats dino? " << myFish.eats(myDino) << endl;
	cout << "Dino eats bear? " << myDino.eats(myBear) << endl;
	cout << "Bear eats fish? " << myBear.eats(myFish) << endl;
}

28.2.3 混入类

如果类在一条轴上组织成层次结构,但他们还与另一条轴有相似之处,混入类将特别有用。此时可在一个类结构中,按照需要加入另一条轴的划分的依据,写成类。之后按照需要从该混入类继承。P661

28.3.1 使用框架

开始使用新框架时,首先要确定框架的工作原理,遵循什么设计原理,开发人员传达的理念是什么,框架广泛使用语言的那些功能。

28.3.2 MVC范型

框架采用的方法与面向对象的设计方法存在差异,常见的是model-view-controller(模型-视图-控制器),来源是:许多应用程序经常处理数据集合,有一个或多个数据视图,还会操纵数据。
MVC中,数据集合成为模型,实践中采用类的形式,包含多个获取器和设置器。
视图是模型的特定可视化形式,两个视图在同一数据上操作,以不同形式查看相同信息。优点:将数据和显示分开后,可以更好组织代码,方便创建其他视图。
控制器是一段代码,通过更改模型来响应一些事件。也可操纵视图。

第二十九章 应用设计模式-待补充

第三十章 开发跨平台和跨语言应用程序

30.1 跨平台开发

30.1.1 架构问题

1.整数大小。<cstdint> 中规定了一些整数类型实际大小
2.二进制兼容性。cpu的指令不同。不同平台需重新编译
3.地址大小。整数大小和指针大小未必一样。
3.字节顺序。大小端。

30.1.2 实现问题

不同编译器对C++标准解释不同。
不同的库对C++实现也不同

30.1.3 平台专用功能

1.图形界面 Qt wxWidgets
2.联网 抽象的套接字socket
3.OS事件和引用程序交互 C++很少与操作系统交互,不直接支持诸如复制和粘贴的操作,可以用库实现,如图形库
4.低级文件 通过系统API实现文件操作
4.线程 C++17已有,或者第三方

30.2跨语言开发–待补充

C和C++
C支持变长数组,C++不支持

//extern关键字告知编译器,链接的代码时C++编译
extern "C++" {
	void fun(int i);
}
//更常见的是头文件级别,将头文件打包到extern块中,以
//指定定义函数的整个头文件是C编写的
extern "C"{
	#include "graphicslib.h"
}

//另一个常见模型是编写单个头文件,然后根据条件针对C或C++编译
#ifdef __cplusplus
	extern "C" {
#endif
	fun1();
#ifdef __cplusplus
	} //matches extern "C"
#endif

C#调用C++代码
以下代码将编译为dll库,接收Unicode字符串,返回一个整数

import <iostream>;
using namespace std;
extern "C"
{	//vs处理方式,输出dll
	__declspec(dllexport) int functionInDLL(const wchar_t* p)
	{
		wcout << L"The following string was received by C++:\n    '";
		wcout << p << L"'" << endl;
		return 42;    // Return some value...
	}
}

using System;
using System.Runtime.InteropServices;

namespace HelloCSharp
{
    class Program
    {	//此处动态引入dll,告知C#从何处查找函数实现,编码为Unicode
        [DllImport("HelloCpp.dll", CharSet = CharSet.Unicode)]
        //指定函数的实际圆形。
        public static extern int functionInDLL(String s);

        static void Main(string[] args)
        {
            Console.WriteLine("Written by C#.");
            int result = functionInDLL("Some string from C#.");
            Console.WriteLine("C++ returned the value " + result);
        }
    }
}

附录A C++面试

附录D UML简介

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值