c++学习笔记(自用)

c++学习记录

第一章:c++简介

c++的历史:

C语言有很多优点,也有很多不足。如对类型匹配的检查不够严格,基本没有支持代码重用的机制,不支持面向对象等。这使得在用C语言开发大规模的软件时,维护和扩充都比较困难。1980年,贝尔实验室开始对C语言进行改进,为其加入面向对象的特性,这种新语言被称为“带类的c”, 但在后来,c++又引入了一些新的函数库和新的用法,如虚函数(virtual function)、操作符重载(operator overloading)、多重继承(multiple inheritance)、模板(template)、异常处理(exception)、RTTI(Runtime type information)、命名空间(namespace)逐渐纳入,逐步增强了c++的可用。

c++的概述:
  1. c++是在C语言的基础上的一个增强版本
  2. c++可以调用c的代码和库
  3. c++是面向对象编程,c语言是面向过程编程
  4. c++支持泛型编程
c++的标准:

c++98标准(ISO/IEC 14882:1998)

c++11标准(ISO/IEC 14882:2011)

第二章:认识类和对象

第一个helloworld程序
#include <iostream> //标准的输入输出流
using namespace std;//声明一个命名空间,cout对象在std作用下
int main()
{
    //cout标准输出流
    //endl换行
    cout << "hello world" << endl;
	return 0;
}

分析:

#include;预编译指令,引入头文件iostream

std为标准命名空间

cout << “hello world” <<endl;和printf功能相同,输出字符串“hello world”

endl表示换行。

在c++中,头文件不在以.h结尾。一些C语言中常用的头文件在c++中的名字去掉.h并在开头加上字符c列如:

#include

#include

#include

面向过程编程:

面向过程编程思想:分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现

面向对象编程:

对象:世界上任何事物都可以看成一个对象(属性+行为)

面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就可以了。

面向对象的三大特点:

封装:将属性和方法(函数)封装在一起抽象成一个类(结构体),并且对类中的成员加以权限控制。

继承:将一个类中属性和方法继承到另一个类中。

多态:一个接口多种形态(静态多态,动态多态)。

第三章 :c++对c语言的扩展

c++对c的扩展:
冒号作用域:

::运算符是一个作用域,如果::前面什么都没有加,代表是全局作用域。

#include <iostream>
using namespace std;

int a = 100;
void test01()
{
    int a = 10;
    cout << a << endl;//输出局部变量a
    cout << ::a << endl;//输出全局变量a
}

int main()
{
    test01();
    return 0;
}
命名空间:

namespace:本质上作用域,可以更好的控制标识符的作用域。

命名空间可以存放 变量,函数,类,结构体…

命名空间的使用:
  • 命名空间的定义必须在全局范围
  • 命名空间可以重名,重名的命名空间相当于合并操作
  • 命名空间可以嵌套命名空间
  • 命名空间如果没有名字,那么这个命名空间内的所有成员都被编译器加上了static修饰符,只能被当前文件调用,属于内部链接属性
  • 命名空间是可以取别名的 namespace newname = oldname;
#include <iostream>
using namespace std;

namespace A
{
    int a = 10;
    void fun()
    {
        cout << "hello world" << endl;
    }
    struct std
    {};
    class obj
    {};
    void foo(int arg)
    {};
}
void A::foo(int arg)
{
    cout << arg << endl;
}
namespace B
{
    int a = 10;
    int b = 20;
}
namespace B
{
	int c = 30;    
}

namespace C
{
    int a = 100;
    int b = 200;
    namespace D
    {
        int a = 900;
    }
}

void test01()
{
    cout << A::a << endl;
    cout << B::a << endl;
    cout << B::b << endl;
    A::fun();
    cout << B::c << endl;
}
void test02()
{
    cout << C::a << endl;
    cout << C::D::a << endl;
}

void test03()
{
    A::foo(222);
}

int main()
{
    test01();
    return 0;
}
using的声明和编译指令:

using的声明可以使得指定标识符可用.命名空间标识符如果和局部变量标识符同名,程序会报错。

using的编译指令使整个命名空间标识符可用,并且命名空间标识符如果和局部变量标识符同名,不会有冲突,优先使用局部变量。

#include <iostream>
using namespace std;
namespace nameA
{
    int a = 10;
    void foo()
    {
        cout << "hello using" << endl;
    }
}

void test01()
{
    //当using声明的标识符和其他标识符有作用域的冲突时,会产生二义性
    //int a = 100;(报错)
    using nameA::a;
    using nameA::foo;
    cout << a << endl;//cout << nameA::a << endl;
}
void test02()
{
    //int a = 100;(不报错,并打印100)
    using namespace nameA;
    cout << a << endl;
   	foo();
}
int main()
{
    test01();
    return 0;
}
c与c++的其它区别:
全局变量的检测:

c++的编译器对于全局变量的声明和定义有严格的区分

//全局变量
int a;//定义
extern int a;//声明

如果写出以下形式,编译时不会通过

//全局变量
int a;
int a;
所有变量和函数都要有类型:

c++中的函数形参类型必须写,没有返回值不可以返回,实参的个数要做检测。

更严格的类型转换:

c++不同类型的变量不能直接赋值的,需要相应的强转。

struct类型增强:

在c++中使用结构体时,可以不写struct关键字。

struct stu
{
    int a;
    int b;
};

int main()
{
    stu obj;//C语言中为 struct stu obj;
}
新增bool类型关键字:

在C语言中使用bool类型需要导入stdbool.h头文件,而c++可以直接使用bool类型变量。

三目运算符的增强:

在c语言中三目运算符返回的是表达式的值,是一个常量

而在c++中三目运算符返回的是一个变量。

int main()
{
	int a = 10;
	int b = 20;
	(a < b ? a : b) = 100;//编译可以通过
}
c/c++的const:

const是一个关键字,用来限定一个变量不允许改变,他将一个对象转换成一个常量。const修饰的常量不能改变

C语言:

  1. C语言修饰的局部变量存在栈区,虽然不能通过变量赋值修改,但是可以通过指针修改
  2. const修饰的全局变量是保存在常量区,不能通过变量赋值和指针修改
  3. const修饰的全局变量,如果其他文件想使用,直接extern声明外部即可使用
#include <stdio.h>
const int b = 10;//const修饰的全局变量保存在常量区

void test01()
{
   
    extern const int num;//声明num是外部可用
    printf("num = %d\n",num);
}

void test02()
{
   
    int *p = &b;
    *p = 100;//错误的 不能修改常量区的值
    printf("b = %d\n",b);
}

void test03()
{
   
    const int a = 10;//C语言中的const修饰的变量保存在栈区
    int *p = &a;
    *p = 100;
    printf("a = %d\n",a);
}

int main()
{
   
    test03();
    return 0;
}

c++

  1. const修饰的局部变量赋值为常量时,局部变量保存在符号表中,不能修改,是一个常量
  2. const修饰的全局变量保存在常量区,不能修改
  3. const修饰的全局变量默认是内部链接属性,加上extern修饰变成外部链接属性
  4. const修饰的全局变量在常量区分配了内存
  5. 对const修饰的局部变量赋值为常量时,对其取地址,会在栈区分配临时的内存空间
  6. const修饰的静态成员变量保存在常量区,不可以修改,在内存中只有一份
#include <iostream>
using namespace std;

void test01()
{
    const int a = 10;
    int *p = (int *)&a;//对const修饰的局部变量区地址,编译器会产生一个临时的变量tmp来保存a的地址
    *p = 100;
    cout << a << endl;
}

int main()
{
    test01();
    return 0;
}
void teest01()
{
	int b = 2;
	const int a = b;
	int *p = (int *)&a;
	*p = 100;
	cout << a << endl;//a的值被修改了
}
struct stu{
	int a;
	int b;
};

int main()
{
	const stu obj  = {1,2};
	struct stu *p =(struct stu *)&obj;
	p -> a = 3;
	p -> b = 4;
	cout << a << " " << b << endl;//修改ab的值
}

c和c++的异/同:

  1. c和c++中的const修饰的全局变量是保存在常量区,不能被修改
  2. c语言中const修饰的局部变量赋值为常量时,局部变量保存在栈区,可以被指针修改
  3. c++中的const修饰的局部变量赋值为常量时,局部变量保存在符号表中,不能修改
  4. C语言中const修饰的全局变量默认是外部链接属性
  5. c++中const修饰的全局变量默认是内部链接属性
引用:

引用的用法:原类型 &别名 = 旧名 (类型名 & 引用名 = 同类型的某变量名)

引用: 为对象起另一个名字,引用类型引用另一种类型。

引用能起到指针的部分作用,但是比指针安全。一个引用可以看作是某个变量的一个"别名"。对引用进行操作就像对原变量进行操作一样。

注意事项:

  1. 引用一旦初始化,不能更改引用的指向
  2. 引用定义时必须初始化
  3. 不能引用NULL
  4. 引用可以引用任意类型包括数组
  5. &在等号左边是引用,在右边是取地址
int a = 10;
int &b = a;
b = 100;
int c = 1;
b = c;//把c的值给b,不是给c取别名
int a = 1;
int &b = a;
b = 2;
cout << a << endl;//输出2
cout << b << endl;//输出2
a = 3;
cout << b << endl;//输出3
int a[5] = {1,2,3,4,5};
int &arr[5] = a;

函数中的引用:

  1. 不能返回局部变量的引用
  2. 引用可以作为函数的形参
#include <iostream>
using namespace std;

void swap(int *x,int *y)
{
    tmp = *x;
    *x = *y;
    *y = tmp;
}

void swap_ref(int &x,int &y)//int &x = a,int &y = b
{
    int tmp = x;
    x = y;
    y = tmp;
}

void get_mem(int **q)//开辟空间
{
    *q = (int *)malloc(5*sizeof(int));
}

void get_mem_ref(int *&q)//int * &q  = p
{
    q = (int *)malloc(5*sizeof(int));
}

void test01()
{
    int a = 10;
    int b = 20;
    swap(&a,&b);
    cout << a << " " << b << endl;
}

void test01_ref()
{
    int a = 10;
    int b = 20;
    swap_ref(a,b);
    cout << a << " " << b << endl;
}
void test02()
{
    int *p = NULL;
    get_mem(&p);
    get_mem_ref(p);
}

int main()
{
	test01_ref();   
}
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
int n = 4;
int & test01()
{
	return n;//返回对n的引用
}
int main()
{
	test01() = 40;//返回值是引用的函数调用表达式,可以作为左值
	cout << n << endl;//输出40
	int& r = test01();
	cout << r << endl;//输出40
}

引用的本质在c++内部实现是一个指针常量

type &b = a;在编译器中是:type *const b = &a;

int a = 10;
int &b = a;//编译器优化 	int * const b = &a;
b = 1000//*b = 1000
//指针常量不能改变指针变量的指向	 b = 0x1000
void fun(int *&q)//int *&q = p ==>int * const q = &p

四,指针的引用

type &q = p

type为指针p的类型

void fun(int *&q)//int *&q = p
{
	
}
int main()
{
	int *p = NULL;
	fun(p);
}	

五,常量的引用

const type &p = q;

常量的引用代表不能通过引用去修改引用标识的那块空间

内联函数:

1.为什么要有内联函数:

第一个在c中也会出现,宏看起来像一个函数调用,但是会有隐藏一些难以发现的错误。

第二个问题c++独有的,预处理器不允许访问类的成员,也就是说预处理器宏不能类的成员函数。

内联函数就是继承了宏函数的高效,并且不会出错,还可以当成类的成员函数用。

2.宏函数和内联函数的区别:

  1. 宏函数替换发生在预处理阶段
  2. 内联函数替换发生在编译阶段
  3. 宏函数容易出错,内联函数不会出错
  4. 内联函数和宏函数一样省去了调用函数的开销
#include <iostream>
using namespace std;
#define MYADD(a,b) a+b

inline int myadd(int a, int b)
{
    return a + b;
}

void test01()
{
    int a = 1;
    int b = 2;
    int c = MYADD(a,b);//a+b,替换发生在预处理阶段
    //int c = MYADD(a,b)*5;//a+b*5,替换发生在编译阶段
    int d = myadd(a,b)*5;//(a+b)*5,替换发生在编译阶段,也和宏函数一样不会有调用函数的开销
    cout << c << endl;
}
int main()
{
    test01();
}

3.内联函数的概念:

在c++中,预定义宏的概念是用内联函数实现的,而内联函数本身也是一个真正的函数,内联函数具有普通函数的所有行为,唯一不同之处在于内联函数会在适当的地方像预定义宏一样展开,多以不需要函数调用的开销,因此不应该使用宏,而是内联函数。

在普通函数前面加上inline关键字使之成为内联函数,但是必须注意函数体和声明结合在一起,否则编译器将他作为普通函数处理

inline int fun(int a)(return ++);

内联函数的确占用空间,但是内联函数相对于普通函数的优势只是省去了函数调用时的压栈,跳转,返回的开销,我们可以理解内联函数是以空间换时间。

4.类的成员函数默认编译器会将它做成内联函数

任何在类内部定义的函数自动成为内联函数。

class Person{
public:
Person() {cout << "构造函数" << endl;}
void PrintPerson() {cout << "输出Person" << endl;}
}

5.内联函数和编译器:

不能存在任何形式的循环语句

不能存在过多的的条件判断

函数体不能过大

不能对函数进行去地址操作

内联函数仅仅是给编译器一个建议,编译器不一定会接受这种建议,如果你没有将函数声明为内联函数,那么编译器也可能将此函数做内联函数,一个好的编译器将会内联小的,简单的函数。

函数的默认参数:

c++中的函数,形参可以设置默认参数,设置时需要注意以下几点:

  1. 设置默认参数时ÿ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值