C C++ 是干什么的

wKiom1dw4tWw3qlfAAK2ySBEJZM611.png


1简单的C++ Hello World!

#include "iostream"     
using namespace std;

int main()
{
        cout << "Hello World!\n" ;//<< endl;
        cout << "Hello World!" << endl;
        return 0;
}
编译运行:
chunli@Linux:~/c++$ g++ main.cpp  && ./a.out 
Hello World!
Hello World!
chunli@Linux:~/c++$



2面向对象的认识:

求圆的面积,过程方法

#include "iostream"     
using namespace std;

int main()
{
        double r = 0;
        double s = 0;
        cout << "请输入圆的半径:" ;//<< endl;
        cin >> r;
        s = 3.1415926 * r * r;
        cout <<"圆的面积是:"<< s << endl;
        return 0;
}
编译:
chunli@Linux:~/c++$ g++ main.cpp  && ./a.out 
请输入圆的半径:10
圆的面积是:314.159


求圆的面积,面向对象方法

#include "iostream"     
using namespace std;
//类是一个数据类型,(固定大小内存块的别名);
//定义一个类,是一个抽象的概念,不会给你分配内存
//用数据类型定义变量的时候,才会分配内存
class MyCicle
{
public :
        double m_s;
        double m_r;
        void set_R(double r)
        {
                m_r = r;
        }       
        double gets() 
        {
                return 3.1415926 * m_r * m_r;
        }
};

int main()
{
        MyCicle my1;
        double r;
        cout << "请输入圆的半径:" ;
        cin >> r;
        my1.set_R(r);
        cout <<"圆的面积是:"<< my1.gets() << endl;
        return 0;
}
编译运行:
chunli@Linux:~/c++$ g++ main.cpp  && ./a.out 
请输入圆的半径:11
圆的面积是:380.133


【经典】初学者易犯错误:

#include "iostream"     
using namespace std;

class MyCicle
{
public :
        double r;
        double s = 3.14 * r *r;
};

int main()
{
        MyCicle my1;
        cout << "请输入圆的半径:" ;
        cin >> my1.r;
        cout <<"圆的面积是:"<< my1.s << endl;
        return 0;
}
编译运行:Lchunli@Linux:~/c++$ g++  -std=c++11 main.cpp  && ./a.out 
请输入圆的半径:10
圆的面积是:0



namespace 1,标准用法:

因为iostream中没有引入标准std,需要程序员手工写

chunli@Linux:~/c++$ cat main.cpp
#include "iostream"
using namespace std;

int main()
{
        cout << "Hello World!"<<endl ;
        return 0;
}
编译运行:
chunli@Linux:~/c++$ g++ main.cpp  && ./a.out 
Hello World!


namespace 2,实际用法:

如果不写 using namespace std ,那么需要显式的引入std

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
//using namespace std;

int main()
{
	std::cout << "Hello World!"<<std::endl ;
	return 0;
}


chunli@Linux:~/c++$ g++ main.cpp  && ./a.out 
Hello World!




自定义namespace

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;


namespace namespaceA
{
	int a ;
}

namespace namaspaceB
{
	int a ;
	namespace namaspaceC
	{
		int a ;
	}
}


int main()
{
	using namespace namespaceA;
	a = 10;
	cout << a <<endl ;
	return 0;
}
编译运行:
chunli@Linux:~/c++$ g++ main.cpp  && ./a.out 
10



两个namespace中含有同样的变量,编译不通过

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;


namespace namespaceA
{
	int a ;
}

namespace namespaceB
{
	int a ;
	namespace namespaceC
	{
		int a ;
	}
}


int main()
{
	using namespace namespaceA;
	using namespace namespaceB;
	a = 10;
	cout << a <<endl ;
	return 0;
}


chunli@Linux:~/c++$ g++ main.cpp  && ./a.out 
main.cpp: In function ‘int main()’:
main.cpp:24:2: error: reference to ‘a’ is ambiguous
  a = 10;
  ^
可以看到不明确a是哪一个




 显式的引用不同namespace中的值

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;


namespace namespaceA
{
	int a ;
}

namespace namespaceB
{
	int a ;
	namespace namespaceC
	{
		int a ;
	}
}


int main()
{
	using namespace namespaceA;
	using namespace namespaceB;
	namespaceA::a = 10;
	namespaceB::a = 20;
	cout << namespaceA::a <<endl ;
	cout << namespaceB::a <<endl ;
	return 0;
}


chunli@Linux:~/c++$ g++ main.cpp  && ./a.out 
10
20


使用嵌套的namespace

#include "iostream"
using namespace std;

namespace namespaceB
{
        int a ;
        namespace namespaceC
        {
                struct Teacher
                {
                        int age;
                };
        }
}


int main()
{
        using namespace namespaceB::namespaceC;
        Teacher t1;
        t1.age  =10;
        cout << t1.age<<endl ;
        return 0;
}

编译:
chunli@Linux:~/c++$ g++ main.cpp && ./a.out 
10

=============================================================================

C++与C的区别:


1

2  register类型增强

chunli@Linux:~/c++$ cat 123.c 
#include <stdio.h>
int main()
{
	register int a = 0;
	printf("%p \n",&a);
	return 0;
}

C语言编译不通过:
chunli@Linux:~/c++$ gcc 123.c && ./a.out 
123.c: In function ‘main’:
123.c:5:2: error: address of register variable ‘a’ requested
  printf("%p \n",&a);
  ^

 C++编译通过:
chunli@Linux:~/c++$ g++ 123.c && ./a.out 
0x7ffe7ac2cc3c


C语言缺陷,C++修复

chunli@Linux:~/c++$ cat 123.c 
#include <stdio.h>
f(i)
{
	printf("i = %d \n",i);
}
g()
{
	return 5;
}
int main()
{
	f(10);
	printf("%d \n",g());
	printf("%d \n",g(1,2,3,4));
	return 0;
}

C语言编译OK
chunli@Linux:~/c++$ gcc 123.c && ./a.out 
i = 10 
5 
5 


C++编译报错:
chunli@Linux:~/c++$ g++ 123.c && ./a.out 
123.c:2:2: error: expected constructor, destructor, or type conversion before ‘(’ token
 f(i)
  ^
123.c:6:3: error: ISO C++ forbids declaration of ‘g’ with no type [-fpermissive]
 g()
   ^


C++对C的加强:

        1 namespace命名空间


1 C++命名空间基本常识

所谓namespace,是指标识符的各种可见范围。C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。

一 :<iostream>和<iostream.h>格式不一样,前者没有后缀,实际上,在你的编译器include文件夹里面可以看到,二者是两个文件,打开文件就会发现,里面的代码是不一样的。后缀为.h的头文件c++标准已经明确提出不支持了,早些的实现将标准库功能定义在全局空间里,声明在带.h后缀的头文件里,c++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h。 因此,

1)当使用<iostream.h>时,相当于在c中调用库函数,使用的是全局命名空间,也就是早期的c++实现;

2)当使用<iostream>的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。

二: 由于namespace的概念,使用C++标准程序库的任何标识符时,可以有三种选择:

1、直接指定标识符。例如std::ostream而不是ostream。完整语句如下: std::cout << std::hex << 3.4 << std::endl;

2、使用using关键字。 using std::cout; using std::endl; using std::cin; 以上程序可以写成 cout << std::hex << 3.4 << endl;

3、最方便的就是使用using namespace std; 例如: using namespace std;这样命名空间std内定义的所有标识符都有效(曝光)。就好像它们被声明为全局变量一样。那么以上语句可以如下写: cout <<hex << 3.4 << endl;因为标准库非常的庞大,所以程序员在选择的类的名称或函数名 时就很有可能和标准库中的某个名字相同。所以为了避免这种情况所造成的名字冲突,就把标准库中的一切都被放在名字空间std中。但这又会带来了一个新问 题。无数原有的C++代码都依赖于使用了多年的伪标准库中的功能,他们都是在全局空间下的。所以就有了<iostream.h> 和<iostream>等等这样的头文件,一个是为了兼容以前的C++代码,一个是为了支持新的标准。命名空间std封装的是标准程序库的名称,标准程序库为了和以前的头文件区别,一般不加".h"





4.2 “实用性”增加


	#include "iostream"
	using namespace std;
	//C语言中的变量都必须在作用域开始的位置定义!!
	//C++中更强调语言的“实用性”,所有的变量都可以在需要使用时再定义。

	int main11()
	{
		int i = 0;

		printf("ddd");
		int k;
		system("pause");
		return 0;
	}


4.3 register关键字增强 


	//register关键字 请求编译器让变量a直接放在寄存器里面,速度快
	//在c语言中 register修饰的变量 不能取地址,但是在c++里面做了内容

	/*
	//1
	register关键字的变化
	register关键字请求“编译器”将局部变量存储于寄存器中
	C语言中无法取得register变量地址
	在C++中依然支持register关键字
	C++编译器有自己的优化方式,不使用register也可能做优化
	C++中可以取得register变量的地址

	//2
	C++编译器发现程序中需要取register变量的地址时,register对变量的声明变得无效。

	//3
	早期C语言编译器不会对代码进行优化,因此register变量是一个很好的补充。

	*/
	int main22()
	{
		register int a = 0; 

		printf("&a = %x\n", &a);

		system("pause");
		return 0;
	}


4.4变量检测增强


	/*
	在C语言中,重复定义多个同名的全局变量是合法的
		在C++中,不允许定义多个同名的全局变量
	C语言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上
	int g_var;
	int g_var = 1;

	C++直接拒绝这种二义性的做法。
	*/
	int main(int argc, char *argv[])
	{
		printf("g_var = %d\n", g_var);
		return 0;
	}


 4.5 struct类型加强 

struct类型的加强:

C语言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型

C++中的struct是一个新类型的定义声明

struct Student
	{
		char name[100];
		int age;
	};

	int main(int argc, char *argv[])
	{
		Student s1 = {"wang", 1};
		Student s2 = {"wang2", 2};    
		return 0;
	}



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


	/*
	C++中所有的变量和函数都必须有类型
		C语言中的默认类型在C++中是不合法的


	函数f的返回值是什么类型,参数又是什么类型?
	函数g可以接受多少个参数?
	*/

	//更换成.cpp试试

	f(i)
	{
		printf("i = %d\n", i);

	}

	g()
	{
		return 5;
	}

	int main(int argc, char *argv[])
	{

		f(10);

		printf("g() = %d\n", g(1, 2, 3, 4, 5));


		getchar();	
		return 0;
	}





【总结】:

/*

在C语言中

int f(    );表示返回值为int,接受任意参数的函数

int f(void);表示返回值为int的无参函数

在C++中

int f(  );和int f(void)具有相同的意义,都表示返回值为int的无参函数

*/


C++更加强调类型,任意的程序元素都必须显示指明类型




4.2-4.6属于语法级别的增强。

4.7新增Bool类型关键字 

/*
	C++中的布尔类型
		C++在C语言的基本类型系统之上增加了bool
		C++中的bool可取的值只有true和false
		理论上bool只占用一个字节,
		如果多个bool变量定义在一起,可能会各占一个bit,这取决于编译器的实现

		true代表真值,编译器内部用1来表示
		false代表非真值,编译器内部用0来表示

		bool类型只有true(非0)和false(0)两个值
		C++编译器会在赋值时将非0值转换为true,0值转换为false
	*/
	int main(int argc, char *argv[])
	{
		int a;
		bool b = true;
		printf("b = %d, sizeof(b) = %d\n", b, sizeof(b));

		b = 4;
		a = b;
		printf("a = %d, b = %d\n", a, b);

		b = -4;
		a = b;
		printf("a = %d, b = %d\n", a, b);

		a = 10;
		b = a;
		printf("a = %d, b = %d\n", a, b);

		b = 0;
		printf("b = %d\n", b);

		system("pause");
		return 0;
	}







4.8三目运算符功能增强

1三目运算符在C和C++编译器的表现 


	int main()
	{
		int a = 10;
		int b = 20;

		//返回一个最小数 并且给最小数赋值成3
		//三目运算符是一个表达式 ,表达式不可能做左值
		(a < b ? a : b )= 30;

		printf("a = %d, b = %d\n", a, b); 

		system("pause");

		return 0;
	}




2结论 

1)C语言返回变量的值 C++语言是返回变量本身

C语言中的三目运算符返回的是变量值,不能作为左值使用

C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方

2)注意:三目运算符可能返回的值中如果有一个是常量值,则不能作为左值使用

(a < b ? 1 : b )= 30;

3)C语言如何支持类似C++的特性呢?

====>当左值的条件:要有内存空间;C++编译器帮助程序员取了一个地址而已

思考:如何让C中的三目运算法当左值呢?






C++ bool类型

只要是非0数字赋予bool类型,全部为true

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;
int main()
{
	bool b1 = true;	cout << sizeof(b1) << endl;
	b1 = 10;	cout << b1 << endl;
	b1 = -10;	cout << b1 << endl;
	b1 = 0;		cout << b1 << endl;
	return 0;
}


chunli@Linux:~/c++$ g++ main.cpp && ./a.out 
1
1
1
0
chunli@Linux:~/c++$


C++ 对三目运算符的增强:

chunli@Linux:~/c++$ cat c.c 
#include<stdio.h>
int main()
{
	int a = 10;
	int b = 20;	
	//在C语言中表达式返回值,返回变量的本身
	//在++语言中返回变量本身
	(a < b ? a: b) = 30;
	printf("%d \n",a);
	printf("%d \n",b);
	return 0;
}

chunli@Linux:~/c++$ gcc c.c  && ./a.out 
c.c: In function ‘main’:
c.c:6:17: error: lvalue required as left operand of assignment
  (a < b ? a: b) = 30;
                 ^
chunli@Linux:~/c++$ g++ c.c  && ./a.out 
30 
20





在C语言中如何实现在C++中编译器的效果

C++编译器帮程序员完成了刚才我们的动作

chunli@Linux:~/c++$ cat c.c 
#include<stdio.h>
int main()
{
	int a = 10;
	int b = 20;	
	*(a < b ? &a: &b) = 30;
	printf("%d \n",a);
	printf("%d \n",b);
	return 0;
}

chunli@Linux:~/c++$ gcc c.c  && ./a.out 
30 
20 
chunli@Linux:~/c++$ g++ c.c  && ./a.out 
30 
20



C++  const 基础

#include "iostream"
using namespace std;
int main()
{
        const int a  = 10;
        int const  b  =11;      //与上面的一样
        const int *c ;  //指针指向的内存区域内的数值不能修改
        int * const d;  //指针不能乱指
        const int * const e;    //只读指针
        return 0;
}


const C C++语言中的冒牌货

1,C语言中的const真是个冒牌货

chunli@Linux:~/c++$ cat c.c 
#include<stdio.h>
int main()
{
	const int a = 10;
	int *p = (int *)&a;
	*p  = 20;
	printf("%d \n",a);
	return 0;
}

chunli@Linux:~/c++$ gcc c.c  && ./a.out 
20


2,C++语言中的const真是真货

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;
int main()
{
	const int a = 10;
	int *p = NULL;
	p = (int *)&a;
	*p  = 20;
	cout << a <<endl;
	cout << *p <<endl;

	return 0;
}


chunli@Linux:~/c++$ g++ -Wall main.cpp  && ./a.out 
10
20


const 与define

wKiom1dw4r3QeTFzAAGVOnmSEys460.png

GCC支持这种写法,微软的不支持

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;
int main()
{
	int a =10;
	int b =30;
	int arr[a+b];
	cout << sizeof(arr)/sizeof(int)<<endl;
	
	return 0;
}


chunli@Linux:~/c++$ g++ -Wall main.cpp  && ./a.out 
40



C++编译器cosnt与宏定义 相似之处

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;
#define  a 20
int main()
{
	//int a =10;
	int b =30;
	int arr[a+b];
	cout << sizeof(arr)/sizeof(int)<<endl;
	
	return 0;
}


chunli@Linux:~/c++$ g++ -Wall main.cpp  && ./a.out 
50


宏定义作用范围

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;

void fun1()
{
	#define  a 20
	cout << "Hello World!" << endl;
}
void fun2()
{
	cout << a << endl;
}
int main()
{
	fun1();
	fun2();
	return 0;
}


chunli@Linux:~/c++$ g++ -Wall main.cpp  && ./a.out 
Hello World!
20


取消宏定义

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;

void fun1()
{
	#define  a 20
	cout << "Hello World!" << endl;
	#undef a  	//取消宏定义a
	//#undef   	//取消所有宏定义
}
void fun2()
{
	cout << a << endl;
}
int main()
{
	fun1();
	fun2();
	return 0;
}


chunli@Linux:~/c++$ g++ -Wall main.cpp  && ./a.out 
main.cpp: In function ‘void fun2()’:
main.cpp:13:10: error: ‘a’ was not declared in this scope
  cout << a << endl;
          ^




【引用】


1,基础知识,两个变量的地址是一样的

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;
int main()
{
	int a = 10;
	int &b = a;
	b = 20;
	cout<< a << endl;
	cout<< &a << endl;
	cout<< &b << endl;
	return 0;
}
chunli@Linux:~/c++$ g++ -Wall main.cpp  && ./a.out 
20
0x7ffec647cc94
0x7ffec647cc94
这就是传说中的引用,不能用C语言去思考



1,定义一个引用,而没有引用值,编译报错;

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;
int main()
{
	int a = 10;
	cout << a << endl;
	int &b ;
	return 0;
}


chunli@Linux:~/c++$ g++ -Wall main.cpp  && ./a.out 
main.cpp: In function ‘int main()’:
main.cpp:7:7: error: ‘b’ declared as reference but not initialized
  int &b ;
       ^




引用的实际应用,当函数参数

引用当函数参数不需要初始化

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;

void fun1(int &a,int &b)
{
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
}
void fun2(int *a,int *b)
{
	*a = *a ^ *b;
	*b = *a ^ *b;
	*a = *a ^ *b;
}
int main()
{
	int var1 = 10;
	int var2 = 20;
	cout << var1 << " "<<var2<< endl;
	fun1(var1,var2);
	cout << var1 << " "<<var2<< endl;
	fun2(&var1,&var2);
	cout << var1 << " "<<var2<< endl;
	
	return 0;
}


chunli@Linux:~/c++$ g++ -Wall main.cpp  && ./a.out 
10 20
20 10
10 20
chunli@Linux:~/c++$


复杂数据类型与引用;

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;

struct Teacher
{
	char name[64];
	int age;
};

void fun1(Teacher *p)
{
	cout << p->age << endl;
	p->age = 11;
}

void fun2(Teacher &p)
{
	cout << p.age << endl;
	p.age = 22;
}

void fun3(Teacher p)
{
	cout << p.age << endl;
	p.age = 33;
}
int main()
{
	Teacher t1;
	t1.age = 20;
	fun1(&t1);	cout << "1 " <<  t1.age << endl;
	fun2(t1);	cout << "2 " <<  t1.age << endl;
	fun3(t1);	cout << "3 " <<  t1.age << endl;
	
	return 0;
}


chunli@Linux:~/c++$ g++ -Wall main.cpp  && ./a.out 
20
1 11
11
2 22
22
3 22
chunli@Linux:~/c++$


结构体的引用类型实质

可以看出与指针很像

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;
struct Teacher
{
	char &c;
};
int main()
{
	cout << sizeof(struct  Teacher)<< endl;	
	return 0;
}


chunli@Linux:~/c++$ g++ -Wall main.cpp  && ./a.out 
8




引用的本质,看图

wKioL1dw3qmBIVTsAAJMBQ0-EnI121.png

chunli@Linux:~/c++$ cat  main.cpp 
#include "iostream"	
using namespace std;
void fun1(int &a)
{
	a = 10;
}
void fun2(int *a)
{
	*a = 20;
}

int main()
{
	int var = 0;
	fun1(var);
	cout << var<< endl;	
	fun2(&var);
	cout << var<< endl;	
	return 0;
}


chunli@Linux:~/c++$ g++ -Wall main.cpp  && ./a.out 
10
20




引用的难点:

返回引用数据类型的函数,用什么数据类型来接?

1,用普通变量来接,相当于数值的传递

2,用引用类型数据来接,相当于地址的传递(危险),返回的地址是已经被析构的

GCC会有警告

VS不会有警告

wKioL1dw3rrgfyiNAAGBZMMYKIo417.png

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;
int& fun1()
{
	int a = 10;
	return a;
}


int main()
{
	int  a = fun1();	cout << a<< endl;
	int &b = fun1();	cout << b<< endl;
	
	return 0;
}


chunli@Linux:~/c++$ g++  main.cpp  && ./a.out 
main.cpp: In function ‘int& fun1()’:
main.cpp:5:6: warning: reference to local variable ‘a’ returned [-Wreturn-local-addr]
  int a = 10;
      ^
10
10


函数返回应用类型,变量是全局生命周期

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;
int a = 20;
int& fun1()
{
	return a;
}
int main()
{
	int  a = fun1();	cout << a<< endl;
	int &b = fun1();	cout << b<< endl;
	
	return 0;
}
chunli@Linux:~/c++$ g++  main.cpp  && ./a.out 
20
20



函数当左值,注意变量的生命周期

chunli@Linux:~/c++$ cat main.cpp 
#include "iostream"	
using namespace std;
int a = 20;
int& fun1()
{
	cout << "in fun1 " <<a << endl;
	return a;
}
int main()
{
	//当左值
	fun1() = 100;	cout << "in fun2 " << a<< endl;
	//当右值
	int a  = fun1();
	return 0;
}
chunli@Linux:~/c++$ g++  main.cpp  && ./a.out 
in fun1 20
in fun2 100
in fun1 100