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

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


大纲

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++语言的关系:

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年代在这里开发了这种语言。

[C++之父-本贾尼·斯特劳斯特卢普undefined]    

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>

usingnamespacestd;

intmain(){

   cout<<"hello world"<<endl;

   returnEXIT_SUCCESS;

}

分析:

  • #include<iostream>; 预编译指令,引入头文件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 ::作用域运算符

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

//全局变量

inta=10;

voidtest(){

   //局部变量

   inta=20;

   //全局a被隐藏

   cout<<"a:"<<a<<endl;

}

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

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

//全局变量

inta=10;

//1. 局部变量和全局变量同名

voidtest(){

   inta=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怎么做?

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

cout<<"全局攻击力为: "<<::atk<<endl;

  1. class scope(类作用域符),用法(class::name)
  2. 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);

他们算是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>

usingnamespacestd;

voidgoAtk();

game.cpp源文件代码:

#include"game1.h"

voidgoAtk()

{

   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;

}

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

语法:

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

{}

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

预览所以的窗格

代码测试

//一个.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. 命名空间下,可以放函数、变量、结构体,类

  1. 命名空间必须定义在全局作用域下
  2. 命名空间可以嵌套命名空间

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

等同于:

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. 命名空间可以起别名(很少用)

  • 创建一个命名空间:

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声明可使得指定的标识符可用。

注意避免二义性问题

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编译指令使整个命名空间标识符可用.

我们再写一个函数

可以看出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下编译通过.

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 <iostream>

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++中返回的是变量

写在最后

为了巩固每日的学习,我推荐大家多逛逛这个地方

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

目录
相关文章
|
2月前
|
安全 程序员 编译器
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
86 11
|
3月前
|
存储 安全 编译器
【C++核心】一文理解C++面向对象(超级详细!)
这篇文章详细讲解了C++面向对象的核心概念,包括类和对象、封装、继承、多态等。
28 2
|
2月前
|
存储 编译器 C语言
【C++】初识面向对象:类与对象详解
【C++】初识面向对象:类与对象详解
|
4月前
|
存储 安全 数据处理
【C++】C++ 超市会员卡管理系统(面向对象)(源码+数据)【独一无二】
【C++】C++ 超市会员卡管理系统(面向对象)(源码+数据)【独一无二】
|
4月前
|
算法 数据可视化 C++
【C++】C++ 学生信息管理系统(源码+面向对象)【独一无二】
【C++】C++ 学生信息管理系统(源码+面向对象)【独一无二】
|
5月前
|
存储 开发框架 Java
|
5月前
|
Java C++ iOS开发
|
6月前
|
C++
C++ 是一种面向对象的编程语言,它支持对象、类、继承、多态等面向对象的特性
C++ 是一种面向对象的编程语言,它支持对象、类、继承、多态等面向对象的特性
|
6月前
|
存储 算法 安全
面向对象程序设计C++
面向对象程序设计C++
|
6月前
|
程序员 数据安全/隐私保护 C++
C++面向对象的四大特征
C++面向对象的四大特征
44 0