面向对象之【探索C++】硬核 | 造轮子的快乐源泉

暑假炎热,我给大家带来一篇解暑博文,来一起和我造轮子

在这里插入图片描述

在这里插入图片描述

大纲

image-20220712204309308

1. C++概述

“c++”中的++来自于c语言中的递增运算符++,该运算符将变量加1。c++起初也叫”c with clsss”.通过名称表明,c++是对C的扩展,因此c++是c语言的超集,这意味着任何有效的c程序都是有效的c++程序。c++程序可以使用已有的c程序库。

库是编程模块的集合,可以在程序中调用它们。库对很多常见的编程问题提供了可靠的解决方法,因此可以节省程序员大量的时间和工作量。

c++语言在c语言的基础上添加了面向对象编程泛型编程的支持。c++继承了c语言高效,简洁,快速和可移植的传统。

c++融合了3种不同的编程方式:

  1. c语言代表的过程性语言.
  2. c++在c语言基础上添加的类代表的面向对象语言.
  3. c++模板支持的泛型编程。

c语言和c++语言的关系:

扫描二维码关注公众号,回复: 14375397 查看本文章

c++语言是在C语言的基础上,添加了面向对象、模板等现代程序设计语言的特性而发展起来的。两者无论是从语法规则上,还是从运算符的数量和使用上,都非常相似,所以我们常常将这两门语言统称为**“C/C++”。**

C语言和C++并不是对立的竞争关系:

1)C++是C语言的加强,是一种更好的C语言。

2)C++是以C语言为基础的,并且完全兼容C语言的特性。

c语言和C++语言的学习是可以相互促进。学好C语言,可以为我们将来进一步地学习C++语言打好基础,而C++语言的学习,也会促进我们对于C语言的理解,从而更好地运用C语言。

1-2 C++起源

与c语言一样,c++也是在贝尔实验室诞生的,Bjarne Stroustrup(本贾尼·斯特劳斯特卢普)在20世纪80年代在这里开发了这种语言。

img

Stroustrup关心的是让c++更有用,而不是实施特定的编程原理或风格。在确定语言特性方面,真正的编程比纯粹的原理更重要。Stroustrup之所以在c的基础上创建c++,是因为c语言简洁、适合系统编程、使用广泛且与UNIX操作系统联系紧密。

用他自己的话来说,“C++主要是为了我的朋友和我不必再使用汇编语言、C语言或者其他现代高级语言来编程而设计的。它的主要功能是可以更方便得编写出好程序,让每个程序员更加快乐”。

1-3 可移植性和标准

假设为运行windows 2000的老式奔腾pc编写了一个很好用的c++程序,而管理员决定使用不同操作系统(比如说Mac OS 或 Linux)和处理器的计算机替换它。该程序是否可在新平台运行呢?当然,但是必须使用为新平台设计的c++编译器重新编译。但是是否需要修改写好的代码?如果不需要修改代码的情况下,重新编译程序后,程序依然运行良好,该程序是可移植的。

程序是否可移植性有两个问题需要解决。第一是硬件,针对特定硬件编程的程序是不可移植的。第二,语言的实现,windows xp c++ 和 Redhat Linux 或 Mac OS X对c++的实现不一定相同。虽然我们希望c++版本与其他版本兼容,但是如果没有一个公开的标准,很难做到。因此,美国国家标准局(American National Standards Institute,ANSI)在1990年设立一个委员会专门负责制定c++标准(ANSI制定了c语言的标准)。国际标准化组织(International Organization for Standardization,ISO)很快通过自己的委员会加入到这个行列,创建了联合组织ANSI/ISO,制定c++标准。

经过多年的努力,制定出了一个国际标准ISO/IEC 14882:1998 ,并于1998年获得了ISO、IEC(International Electrotechnical Committee,国际电工技术委员会)和ANSI的批准。这个标准就是我们经常所说的c++98。它不仅描述了已有的c++特性,还对语言进行了扩展,添加了异常、运行阶段类型识别(RTTI)、模板和标准模板库(STL).

2003年,发布了c++标准第二版(IOS/IEC 14882:2003),这一版本对第一版修订了一些错误,但并没有改变语言特性,因此c++98表示c++98/c++2003.

c++不断发展。IOS标准委员会于2011年8月批准了新标准ISO/IEC 14882:2011,该标准被称为c++11,与c++98一样c++11也新增了许多特性。

ISO c++标准还吸收了ANSI c语言标准,c++尽量做到是c的超集。意味着在理想情况下,任何有效的c程序都应该是有效的c++程序。

ANSI不仅定义了c语言,还 定义了一个ANSI c必须实现的标准c库。c++也在使用这个库,另外ANSI/ISO c++标准还提供了一个c++标准类库。、

1-4 为什么C++会成功

c++最初的目的是将c语言转变为OOP(面向对象程序设计)语言,但是c++后来并没有这么做,而是立足于程序的实际。因为在c语言方面大量投入的程序员使其完全丢掉c语言那种编程的思考方式,转而去接受一种新的语言,新的思维,那么将会导致这些程序员中大部分人在短时间内可能毫无成果,使其生产率降低。但是如果让这些c程序员在已有知识的基础上,再去学习c++语言,理解运用OOP,那么也只是在其已有思维的基础上进行扩展而已,这样可以保持其更好的生产率。

简而言之,强迫程序员放弃c语言和c语言的思考方式,而去转到OOP上是需要代价的,但是从c语言转到c++所花费的代价就会小很多。所以也可以理解为c++的出现并不是去替代c,而是对c的扩展,所以在c++中既可以使用c++新特性,并且可以使用c的过程式思维来编写程序。

对于传统的结构化语言,我们向来没有太多的疑惑,函数调用那么自然而明显,只是从程序的某一个地点调到另一个地点去执行。但是对于面向对象(OO)语言,我们疑惑就会很多。其原因就是c++编译器为我们程序员做了太多隐藏的工作:构造函数,析构函数、虚函数、继承、多态…有时候它为我们合成出一些额外的函数,有时候它又偷偷在我们写的函数里,放进更多的操作。有时候也会给我们的对象里放进一些奇妙的东西,使得我们sizeof的时候结果可我们预期不一样。

2. C++初始

2.1 简单的C++程序

2.1.1 C++ hello world

示例代码:

#include<iostream>
using namespace std;

int main(){	
	cout << "hello world" << endl;
	return EXIT_SUCCESS;
}

分析:

  • #include; 预编译指令,引入头文件iostream.
  • using namespace std; 使用标准命名空间
  • cout << “hello world”<< endl; 和printf功能一样,输出字符串”hello wrold”

问题1:c++头文件为什么没有.h?

在c语言中头文件使用扩展名.h,将其作为一种通过名称标识文件类型的简单方式。但是c++得用法改变了,c++头文件没有扩展名。但是有些c语言的头文件被转换为c++的头文件,这些文件被重新命名,丢掉了扩展名.h(使之成为c++风格头文件),并在文件名称前面加上前缀c(表明来自c语言)。例如c++版本的math.h为cmath.

由于C使用不同的扩展名来表示不同文件类型,因此用一些特殊的扩展名(如hpp或hxx)表示c++的头文件也是可以的,ANSI/IOS标准委员会也认为是可以的,但是关键问题是用哪个比较好,最后一致同意不适用任何扩展名。

头文件类型 约定 示例 说明
c++旧式风格 以.h结尾 iostream.h c++程序可用
c旧式风格 以.h结尾 math.h c/c++程序可用
c++新式风格 无扩展名 iostream c++程序可用,使用namespace std
转换后的c 加上前缀c,无扩展名 cmath c++程序可用,可使用非c特性,如namespace std

问题2:using namespace std 是什么?

namespace是指标识符的各种可见范围。命名空间用关键字namespace 来定义。命名空间是C++的一种机制,用来把单个标识符下的大量有逻辑联系的程序实体组合到一起。此标识符作为此组群的名字。

问题3:cout 、endl 是什么?

cout是c++中的标准输出流,endl是输出换行并刷新缓冲区。

问题4:iostream是什么?

一个库:iostream库包含两个基础类型istream和ostream,分别表示输入流和输出流

2.1.2 面向过程

面向过程是一种以过程为中心的编程思想。

通过分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。

面向过程编程思想的核心:功能分解,自顶向下,逐层细化**(程序=数据结构+算法)**。

面向过程编程语言存在的主要缺点是不符合人的思维习惯,而是要用计算机的思维方式去处理问题,而且面向过程编程语言重用性低,维护困难。

2.1.3 面向对象

面向对象编程(Object-Oriented Programming)简称 OOP 技术,是开发计算机应用程序的一种新方法、新思想。过去的面向过程编程常常会导致所有的代码都包含在几个模块中,使程序难以阅读和维护。在做一些修改时常常牵一动百,使以后的开发和维护难以为继。而使用 OOP 技术,常常要使用许多代码模块,每个模块都只提供特定的功能,它们是彼此独立的,这样就增大了代码重用的几率,更加有利于软件的开发、维护和升级。

在面向对象中,算法与数据结构被看做是一个整体,称作对象,现实世界中任何类的对象都具有一定的属性和操作,也总能用数据结构与算法两者合一地来描述,所以可以用下面的等式来定义对象和程序:

​ 对象 = 算法 + 数据结构

​ 程序 = 对象 + 对象 + ……

从上面的等式可以看出,程序就是许多对象在计算机中相继表现自己,而对象则是一个个程序实体。

面向对象编程思想的核心:应对变化,提高复用。

2.1.5 面向对象三大特性

  • 封装

    把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

    类将成员变量和成员函数封装在类的内部,根据需要设置访问权限,通过成员函数管理内部状态。

  • 继承

    继承所表达的是类之间相关的关系,这种关系使得对象可以继承另外一类对象的特征和能力。

    继承的作用:避免公用代码的重复开发,减少代码和数据冗余。

  • 多态

    多态性可以简单地概括为“一个接口,多种方法”,字面意思为多种形态。程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。

3. C++对C的扩展

3.1 ::作用域运算符

通常情况下,如果有两个同名变量,一个是全局变量,另一个是局部变量,那么局部变量在其作用域内具有较高的优先权,它将屏蔽全局变量。

//全局变量
int a = 10;
void test(){
	//局部变量
	int a = 20;
	//全局a被隐藏
	cout << "a:" << a << endl;
}

程序的输出结果是a:20。在test函数的输出语句中,使用的变量a是test函数内定义的局部变量,因此输出的结果为局部变量a的值。

作用域运算符可以用来解决局部变量与全局变量的重名问题

//全局变量
int a = 10;
//1. 局部变量和全局变量同名
void test(){
	int a = 20;
	//打印局部变量a
	cout << "局部变量a:" << a << endl;
	//打印全局变量a
	cout << "全局变量a:" << ::a << endl;
}

这个例子可以看出,作用域运算符可以用来解决局部变量与全局变量的重名问题,即在局部变量的作用域内,可用::对被屏蔽的同名的全局变量进行访问。

比如声明了一个类A,类A里声明了一个成员函数voidf(),但没有在类的声明里给出f的定义,那么在类外定义f时,就要写成voidA::f(),表示这个f()函数是类A的成员函数。例如

classCA {
public: 
  intca_var;  
  intadd(inta, intb);  
  intadd(inta);  
};
   
//那么在实现这个函数时,必须这样书写: 
intCA::add(inta, intb)  
{
  returna + b;  
}
   
//另外,双冒号也常常用于在类变量内部作为当前类实例的元素进行表示,比如: 
intCA::add(inta)  
{ 
  returna + ::ca_var;  
}
//表示当前类实例中的变量ca_var。

3.2 名字控制

创建名字是程序设计过程中一项最基本的活动,当一个项目很大时,它会不可避免地包含大量名字。c++允许我们对名字的产生和名字的可见性进行控制。

我们之前在学习c语言可以通过static关键字来使得名字只得在本编译单元内可见,在c++中我们将通过一种通过命名空间来控制对名字的访问。

:: 是作用域符,是运算符中等级最高的,它分为三种:

  1. global scope(全局作用域符),用法(::name)

    我们看下面一个例子,如果我需要输出全局变量200怎么做?

    image-20220712102735067

    看下面的语句,发现多了两个冒号——作用域运算符

    image-20220712104452757

    cout<<"全局攻击力为: "<<::atk<<endl;
    
  2. class scope(类作用域符),用法(class::name)

  3. namespace scope(命名空间作用域符),用法(namespace::name)

    他们都是左关联(left-associativity),他们的作用都是为了更明确的调用你想要的变量:

1.如在程序中的某一处你想调用全局变量a,那么就写成::a;(也可以是全局函数)

2.如果想调用class A中的成员变量a,那么就写成A::a;

3.另外一个如果想调用namespace std中的cout成员,你就写成std::cout(相当于using namespace std;cout)意思是在这里我想用cout对象是命名空间std中的cout(即就是标准库里边的cout);

image-20220712105146485

他们算是C++中的基础,如果运用的好的话,你程序的出错率也许会降很多,o~~~~~~~~~

二、
(1)表示“域操作符”
例:声明了一个类A,类A里声明了一个成员函数void f(),但没有在类的声明里给出f的定义,那么在类外定义f时, 就要写成void A::f(),表示这个f()函数是类A的成员函数。
(2)直接用在全局函数前,表示是全局函数
例:在VC里,你可以在调用API 函数里,在API函数名前加 ::
(3)表示引用成员函数及变量,作用域成员运算符
例:System::Math::Sqrt() 相当于System.Math.Sqrt();

三、
1、作用域符号::的前面一般是类名称,后面一般是该类的成员名称。
C++为例避免不同的类有名称相同的成员而采用作用域的方式进行区分。
如:A,B表示两个类,在A,B中都有成员member。那么
A::member就表示类A中的成员member,B::member就表示类B中的成员member。

2、全局作用域符号:当全局变量在局部函数中与其中某个变量重名,那么就可以用::来区分,如:

charzhou; //全局变量
voidsleep()
{
    charzhou; //局部变量
    char(局部变量) = char(局部变量) *char(局部变量) ;
    ::char(全局变量) =::char(全局变量) *char(局部变量);
}

3.2.1 C++命名空间

在c++中,名称(name)可以是符号常量、变量、函数、结构、枚举、类和对象等等。工程越大,名称互相冲突性的可能性越大。另外使用多个厂商的类库时,也可能导致名称冲突。为了避免,在大规模程序的设计中,以及在程序员使用各种各样的C++库时,这些标识符的命名发生冲突,标准C++引入关键字namespace(命名空间/名字空间/名称空间),可以更好地控制标识符的作用域。

3.2.2 命名空间namespace使用

在c++中,名称(name)可以是符号常量、变量、函数、结构、枚举、类和对象等等。工程越大,名称互相冲突性的可能性越大。另外使用多个厂商的类库时,也可能导致名称冲突。为了避免,在大规模程序的设计中,以及在程序员使用各种各样的C++库时,这些标识符的命名发生冲突,标准C++引入关键字namespace(命名空间/名字空间/名称空间),可以更好地控制标识符的作用域。

这里我创建了两个头文件为:game1.h 、game2.h 和两个源文件:game1.cpp、game2.cpp

game.h头文件代码:

#include<iostream>
using namespace std;

void goAtk();

game.cpp源文件代码:

#include"game1.h"

void goAtk()
{
	cout<<"王者荣耀攻击实现"<<endl;
}

主程序代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include"game1.h"
#include"game2.h"
int main()
{
	goAtk();
	
	system("pause");
	return EXIT_SUCCESS;
}

image-20220712111355765

运行出错了,解决方法使用命名空间

语法:

namespace name1//主要用途用来解决命名冲突的问题
{}

再看上面的案例,我们在.h文件中使用命名空间

image-20220712180845166

预览所以的窗格

image-20220712181411926

代码测试

//一个.cpp源文件就可以了
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
//game1
namespace LO
{

	void goAtk();

}
void  LO::goAtk()
{
	cout<<"LOL攻击实现"<<endl;
}
//game2
namespace K
{

	void goAtk();

}

void K::goAtk()
{
	cout<<"王者荣耀攻击实现"<<endl;
}

int main()
{
	LO::goAtk();
	K::goAtk();
	system("pause");
	return EXIT_SUCCESS;
}

namespace使用

  1. 命名空间下,可以放函数、变量、结构体,类

image-20220712181923730

  1. 命名空间必须定义在全局作用域下

  2. 命名空间可以嵌套命名空间

image-20220712184311361

  1. 命名空间是开放的,可以随时在原先的命名空间添加内容

image-20220712185146548

等同于:

namespace A{
	int a = 10;
		int b = 1000;
}
  1. 无名、匿名命名空间

    这种很少用,知道有这种写法就行

namespace 
{
	int a = 10;
	int b = 1000;
}
//当写了无名命名空间,相当于写了 static int a;	static int b;(静态变量)
//只能在当前文件内使用

void test(){
	cout << " a为: " << a << endl;
	cout<< "b为:"<< b << endl;
}
  1. 命名空间可以起别名(很少用)

    image-20220712190338011

  • 创建一个命名空间:
namespace A{
	int a = 10;
}
namespace B{	
	int a = 20;
}
void test(){
	cout << "A::a : " << A::a << endl;
	cout << "B::a : " << B::a << endl;
}
  • 命名空间只能全局范围内定义(以下错误写法

    void test(){
    	namespace A{
    		int a = 10;
    	}
    	namespace B{
    		int a = 20;
    	}
    	cout << "A::a : " << A::a << endl;
    	cout << "B::a : " << B::a << endl;
    }
    
  • 命名空间可嵌套命名空间

namespace A{
	int a = 10;
	namespace B{
		int a = 20;
	}
}
void test(){
	cout << "A::a : " << A::a << endl;
	cout << "A::B::a : " << A::B::a << endl;
}
  • 命名空间是开放的,即可以随时把新的成员加入已有的命名空间中

    namespace A{
    	int a = 10;
    }
    
    namespace A{
    	void func(){
    		cout << "hello namespace!" << endl;
    	}
    }
    
    void test(){
    	cout << "A::a : " << A::a << endl;
    	A::func();
    }
    
  • 声明和实现可分离

    #pragma once
    
    namespace MySpace{
    	void func1();
    	void func2(int param);
    }
    
    
    void MySpace::func1(){
    	cout << "MySpace::func1" << endl;
    
    void MySpace::func1(){
    	cout << "MySpace::func1" << endl;
    }
    void MySpace::func2(int param){
    	cout << "MySpace::func2 : " << param << endl;
    }
    
  • 无名命名空间,意味着命名空间中的标识符只能在本文件内访问,相当于给这个标识符加上了static,使得其可以作为内部连接

    namespace{
    	
    	int a = 10;
    	void func(){ cout << "hello namespace" << endl; }
    }
    void test(){
    	cout << "a : " << a << endl;
    	func();
    }
    
  • 命名空间别名

namespace veryLongName{
	
	int a = 10;
	void func(){ cout << "hello namespace" << endl; }
}

void test(){
	namespace shortName = veryLongName;
	cout << "veryLongName::a : " << shortName::a << endl;
	veryLongName::func();
	shortName::func();
}

3.2.3 using声明

using声明可使得指定的标识符可用。

image-20220713215538069

注意避免二义性问题

namespace A{
	int paramA = 20;
	int paramB = 30;
	void funcA(){ cout << "hello funcA" << endl; }
	void funcB(){ cout << "hello funcA" << endl; }
}

void test(){
	//1. 通过命名空间域运算符
	cout << A::paramA << endl;
	A::funcA();
	//2. using声明
	using A::paramA;
	using A::funcA;
	cout << paramA << endl;
	//cout << paramB << endl; //不可直接访问
	funcA();
	//3. 同名冲突
	//int paramA = 20; //相同作用域注意同名冲突
}

using声明碰到函数重载

namespace A{
	void func(){}
	void func(int x){}
	int  func(int x,int y){}
}
void test(){
	using A::func;
	func();
	func(10);
	func(10, 20);
}

如果命名空间包含一组用相同名字重载的函数,using声明就声明了这个重载函数的所有集合。

3.2.4 using编译指令

using编译指令使整个命名空间标识符可用.

image-20220713220704149

我们再写一个函数

image-20220713221021720

可以看出using可以指定函数调用,我需要王者荣耀的就加using namespace KingGlory、要LOL就using namespace LOL

输出也是可以cout<< LOL::sunwukong<<endl;

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

namespace KingGlory
{
	int sunwukongId = 10;
}

//using编译指令
namespace LOL
{
	int sunwukongId = 30;
}
void test02()
{
	//int sunwukongId = 20;
	//using编译指令
	using namespace KingGlory; //打开王者荣耀房间
	using namespace LOL;//打开LOL房间
	//如果打开多个房间,也要避免二义性问题
	cout << LOL::sunwukongId << endl;
    
    //错误写法,没有指定具体哪一个
    //cout << sunwukongId << endl;
    
    
}


int main(){


	test02();
	system("pause");
	return EXIT_SUCCESS;
}

代码意思就是有两个using namespace 1、using namespace 2我们必须指定是具体哪一个

注意:使用using声明或using编译指令会增加命名冲突的可能性。也就是说,如果有名称空间,并在代码中使用作用域解析运算符,则不会出现二义性。

3.2.5 命名空间使用

我们刚讲的一些东西一开始会觉得难一些,这些东西以后还是挺常用,只要理解了它们的工作机理,使用它们非常简单。

需要记住的关键问题是当引入一个全局的using编译指令时,就为该文件打开了该命名空间,它不会影响任何其他的文件,所以可以在每一个实现文件中调整对命名空间的控制。比如,如果发现某一个实现文件中有太多的using指令而产生的命名冲突,就要对该文件做个简单的改变,通过明确的限定或者using声明来消除名字冲突,这样不需要修改其他的实现文件。

3.3 全局变量检测增强

c语言代码:

int a = 10; //赋值,当做定义
int a; //没有赋值,当做声明

int main(){
	printf("a:%d\n",a);
	return EXIT_SUCCESS;
}

此代码在c++下编译失败,在c下编译通过.

image-20220713222602262

3.4 C++中所有的变量和函数都必须有类型

c语言代码:

//i没有写类型,可以是任意类型
int fun1(i){
	printf("%d\n", i);
	return 0;
}
//i没有写类型,可以是任意类型
int fun2(i){
	printf("%s\n", i);
	return 0;
}
//没有写参数,代表可以传任何类型的实参
int fun3(){ 
	printf("fun33333333333333333\n");
	return 0;
}

//C语言,如果函数没有参数,建议写void,代表没有参数
int fun4(void){
	printf("fun4444444444444\n");
	return 0;
}

g(){
	return 10;
}

int main(){

	fun1(10);
	fun2("abc");
	fun3(1, 2, "abc");
	printf("g = %d\n", g());

	return 0;
}

以上c代码c编译器编译可通过,c++编译器无法编译通过。

  • n 在C语言中,int fun() 表示返回值为int,接受任意参数的函数,int fun(void) 表示返回值为int的无参函数。

  • 在C++ 中,int fun() 和int fun(void) 具有相同的意义,都表示返回值为int的无参函数。

动画

左边是C文件右边是cpp,c码红了

3.5 更严格的类型转换

在C++,不同类型的变量一般是不能直接赋值的,需要相应的强转。

c语言代码:

typedef enum COLOR{ GREEN, RED, YELLOW } color;
int main(){

	color mycolor = GREEN;
	mycolor = 10;
	printf("mycolor:%d\n", mycolor);
	char* p = malloc(10);
	return EXIT_SUCCESS;
}

以上c代码c编译器编译可通过,c++编译器无法编译通过。

3.6 struct类型加强

  • c中定义结构体变量需要加上struct关键字,c++不需要。
  • c中的结构体只能定义成员变量,不能定义成员函数。c++即可以定义成员变量,也可以定义成员函数。
//1. 结构体中即可以定义成员变量,也可以定义成员函数
struct Student{
	string mName;
	int mAge;
	void setName(string name){ mName = name; }
	void setAge(int age){ mAge = age; }
	void showStudent(){
		cout << "Name:" << mName << " Age:" << mAge << endl;
	}
};

//2. c++中定义结构体变量不需要加struct关键字
void test01(){
	Student student;
	student.setName("John");
	student.setAge(20);
	student.showStudent();
}

3.7 “新增”bool类型关键字

标准c++的bool类型有两种内建的常量true(转换为整数1)和false(转换为整数0)表示状态。这三个名字都是关键字。

  • bool类型只有两个值,true(1值),false(0值)
  • bool类型占1个字节大小
  • 给bool类型赋值时,非0值会自动转换为true(1),0值会自动转换false(0)
	void test()
{	cout << sizeof(false) << endl; //为1,//bool类型占一个字节大小
	bool flag = true; // c语言中没有这种类型
	flag = 100; //给bool类型赋值时,非0值会自动转换为true(1),0值会自动转换false(0)
}

[c语言中的bool类型]

c语言中也有bool类型,在c99标准之前是没有bool关键字,c99标准已经有bool类型,包含头文件stdbool.h,就可以使用和c++一样的bool类型。

3.8 三目运算符功能增强

  • c语言三目运算表达式返回值为数据值,为右值,不能赋值。
int a = 10;
	int b = 20;
	printf("ret:%d\n", a > b ? a : b);
	//思考一个问题,(a > b ? a : b) 三目运算表达式返回的是什么?
	
	//(a > b ? a : b) = 100;
	//返回的是右值
  • c++语言三目运算表达式返回值为变量本身(引用),为左值,可以赋值。
	int a = 10;
	int b = 20;
	printf("ret:%d\n", a > b ? a : b);
	//思考一个问题,(a > b ? a : b) 三目运算表达式返回的是什么?

	cout << "b:" << b << endl;
	//返回的是左值,变量的引用
	(a > b ? a : b) = 100;//返回的是左值,变量的引用
	cout << "b:" << b << endl;

[左值和右值概念]

在c++中可以放在赋值操作符左边的是左值,可以放到赋值操作符右面的是右值。

有些变量即可以当左值,也可以当右值。

左值为Lvalue,L代表Location,表示内存可以寻址,可以赋值。

右值为Rvalue,R代表Read,就是可以知道它的值。

比如:int temp = 10; temp在内存中有地址,10没有,但是可以Read到它的值。

c源代码

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//1、全局变量检测增强
int a;
int a = 10;

//2、函数检测增强
int getRectS(w, h)
{
    
    
}
void test02()
{
    
    
	getRectS(10, 10, 10);
}

//3、类型转换检测增强
void test03()
{
    
    
	char * p = malloc(sizeof(64)); //malloc返回值是void*
}

//4、struct 增强
struct Person
{
    
    
	int m_Age;
	//void plusAge(); //c语言中struct不可以加函数
};
void test04()
{
    
    
	struct Person p1; //使用时候必须加入struct关键字
}

//5、 bool类型增强 C语言中没有bool类型
//bool flag;

//6、三目运算符增强
void test06()
{
    
    
	int a = 10;
	int b = 20;

	printf("ret = %d \n", a > b ? a : b);

	//a > b ? a : b = 100; // 20 = 100 C语言返回的是值

	//C语言中想模仿C++写
	*(a > b ? &a : &b) = 100;
	printf("a = %d ,b = %d \n", a, b);

}
int main(){
    
    


	system("pause");
	return EXIT_SUCCESS;
}

c++源代码

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//1、全局变量检测增强
//int a;
int a = 10;

//2、函数检测增强 ,参数类型增强,返回值检测增强,函数调用参数检测增强
int getRectS(int w, int h)
{
	return w*h;
}
void test02()
{
	getRectS(10, 10);
}


//3、类型转换检测增强
void test03()
{
	char * p = (char*)malloc(sizeof(64)); //malloc返回值是void*
}


//4、struct 增强
struct Person
{
	int m_Age;
	void plusAge(){ m_Age++; }; //c++中struct可以加函数
};
void test04()
{
	Person p1; //使用时候可以不加struct关键字
	p1.m_Age = 10;
	p1.plusAge();
	cout << p1.m_Age << endl;
}

//5、 bool类型增强 C语言中没有bool类型
bool flag = true; //只有真或假 true代表 真(非0)  false 代表假(0)
void test05()
{
	cout << sizeof(bool) << endl;

	flag = 100;
	//bool类型 非0的值 转为 1  ,0就转为0
	cout << flag << endl;
}

//6、三目运算符增强
void test06()
{
	int a = 10;
	int b = 20;

	cout << "ret = " << (a < b ? a : b) << endl;
	
	(a < b ? a : b) = 100; //b = 100 C++中返回的是变量
	 
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}
int main(){

	//test04();

	// test05();

	// test06();


	system("pause");
	return EXIT_SUCCESS;
}

重点回顾

1 #include

1.1 using namespace std;

1.2 cout << “hello …” << endl;

1.3 system(“pause”)

1.4 retrun 0

2 ::双冒号作用域运算符

2.1 全局作用域 直接加::

3 namespace 命名空间

3.1 用途 解决名称冲突问题

3.2 必须在全局作用域下声明

3.3 命名空间下可以放入 函数、变量、结构体、类…

3.4 命名空间可以嵌套命名空间

3.5 命名空间是开放的,可以随时加入新的成员

3.6 匿名命名空间 static

3.7 可以起别名

4 using声明和using编译指令

4.1 using LOL:: sunwukongID;

4.2 如果局部范围内还有 sunwukongID,会出现二义性问题,要注意避免

4.3 编译指令

4.4 using namespace LOL

4.5 如果局部范围内还有 sunwukongID ,使用局部的ID

4.6 如果打开多个房间,那么也要注意二义性问题

5 C++对C语言增强

5.1 全局变量检测增强

5.2 函数检测增强

5.2.1 参数类型检测

5.2.2 返回值检测

5.2.3 传参个数检测

5.3 类型转换检测增强

5.3.1 malloc返回void* ,C中可以不用强转,C++必须强转

5.4 struct增强

5.4.1 C中不许有函数 C++可以

5.4.2 使用C必须加关键字 struct ,C++可以不加

5.5 bool数据类型增强

5.5.1 C没有 C++有

5.5.2 true 真 false假

5.5.3 sizeof 1

5.6 三目运算符增强

5.6.1 C中返回的是值

5.6.2 C++中返回的是变量

写在最后

为了巩固每日的学习,我推荐大家一款面试刷题找工作神奇牛客网IT人必备

image-20220714113753139

每道题都有可观的数据,有题解和排名

动画
记得点赞收藏哦

猜你喜欢

转载自blog.csdn.net/weixin_51568389/article/details/125785420