Day 1
2、new-delete语法简介:
a)C语言中需要使用malloc与free申请与释放堆空间:
b)C++把堆空间申请与释放做成关键字,底层也是malloc和free。
c)用起来绝对舒服,成为关键字不用包含头文件。
d)就如同栈一样的模式,比如:栈内申请一个数组:int a[20];
堆内:int* p = new int[20];//堆数组,中括号内可以代入变量,如int n=20;int* p=new int[n];
new和delete代替malloc-free特别方便
int n = 20;
int* p = (int*)malloc(sizeof(int)*n);//给我来20个int
//int* p = new int[n];
1、在堆空间上分配和释放单个变量
TYPE * p = new TYPE;
delete p;
类似于栈内的:
int n = 888;
int *p = new int(888);
int *p = new int{888};
SNode* p = new SNode{d};//C++11可以在这把d和NULL带入,
//p->data = d;
//p->pNext = NULL;
2、在堆空间上分配分配和释放数组(多个变量)
TYPE * p = new TYPE[N]; //N可以是变量
delete []p;
类似于栈内的:
double a[N];//栈内申请数组只能是常量
double *p = new double[N];
分配并初始化:double* p=new double [n]{88,98,34,33};
注意:申请时带中括号[],释放时也要delete []p;
3、在堆空间上分配和释放指针数组;
auto p = new const char* [] { "abc", "efg", "test", nullptr };
delete []p;
单个堆变量专题:
int main()
{//98版本的C++
int* p = new int;
*p = 888;
delete p;
return 0;
}
int* p = new int(888);//C++98
int* p = new int{ 888 };//C++11
int main()
{//2011版本的C++
int* p = new int{ 888 };
delete p;
return 0;
}
//c++在堆区创建二维数组
98版C++支持堆二维数组(不支持初始化): double (*p)[12] = new double[3][12];
11版C++支持初始化:double (*p)[12] = new double[3][12]{{12,4,6},{22,33,5,55}};
int main()
{//2011版本的C++
SData data = { 1002,"Alice",8983.55f };
SData* p = new SData{ 1002,"Alice",8983.55f };
delete p;
return 0;
}
3、cin和cout语法简介:
a)C++系统的头文件不加.h,故意可以防止与自己的头文件冲突。
b)cin和cout最大的特点就是类型自动识别,比printf的%d,%f要好用多了
c)cin的时候也不用取地址,为什么呢?实际上内部语法是引用型变量(自动转帮你取地址)。
d)cout <<"\n"一般会使用cout << endl;代替//end of line
cout 不足之处是占位不如printf("%-8.2f"..)好用。
4、namespace命名空间:
a)这个语法是为了解决变量和函数名字冲突;
b)比如每个程序员用自己的姓名作为分类名称,namespace类似加了一个外壳。
c)using namespace xxx,就代表把壳去掉。
#include <iostream>
using namespace std;
namespace LVXIN
{
double g1 = 0.8;
int add(int a, int b)
{
return a + b;
}
}
double g1;
//名字 空间
int main()
{
LVXIN::g1 = 888.88;
LVXIN::add(6, 8);//虽然这个语法很烂,也或许是C++类的起源语法。
g1 = 999;
cout << "LVXIN::g1的地址:" << &LVXIN::g1 << endl;
cout << "g1的地址:" << &g1 << endl;
return 0;
//如果加上using namespace LVXIN,
LVXIN::g1 = 888.88;g1 = 999;这两个语句会发生冲突
修正:LVXIN::g1 = 888.88;::g1 = 999;(::g1前面两个冒号代表无壳,表示不属于任何命名空间)
}
Day 2
引用型变量:
a)C++掩盖真相的语法之一,其内部真实原理就是指针变量。
b)引用做参数时主调函数好用,替你取地址,被调函数也好用,不用*符号;
c)类似于指针常量,指针常量的意思就是指向某个地址,在生命期内再不能改了;
d)另外指针常量的特点是必须初始化,引用型变量必须在定义的同时挂在某个变量上。
#include <iostream>
int main()
{
int m = 888,n=-1;
int* const p;//错误,必须初始化
int* const p = &m;
p = &n;//错误,初始化后就不能再指向别的变量
int& k;//错误,必须初始化
int& k = n;
k = 0;//等价于*p = 0;
k = m;//这个语句是赋值不是挂载语法
return 0;
}
Day3
3.2 vector系统类库分析
2、C++封装类的高明:有两项高明
a)通过封装类,程序员可以定义任意多的动态数组对象(链表对象等)
(你想想C语言能实现吗?)
b)模板技术也叫泛型技术,程序员可以定义任意多种类型的数据来使用算法类。
比如:
vector<double> v1;
vector<SInfo> v2;
3、this指针的原理:
a)没有真正的成员函数,类内没有函数,C++是隐藏了真相的语言。
b)真实的情况是每个成员函数内都有一个this,指针变量指向来源对象。
c)在成员函数运算过程中,可以调用this指针指向的对象内的数据。
#include <iostream>
using namespace std;
const float PI = 3.14159f;
struct Circle
{
double radius;
double Circumference() //圆周长 struct Circle* const this,this指针的类型是struct Circle* const
{
this = NULL;//错误,因为有const,所有this指向的内容不能改变
this++;//错误,因为有const,所有this指向的内容不能改变
return 2 * PI * this ->radius;
}
double Area() //圆面积
{
return PI * this->radius * this ->radius;
}
};
int main()
{
float radius;
cout << "sizeof(struct Circle)=" << sizeof(struct Circle) << endl;
cout << "请输入游泳池的半径: ";
cin >> radius;
// 声明 Circle 对象
Circle Pool = { radius };
Circle PoolRim = { radius + 3 };
//计算栅栏长度
cout << "栅栏长度是:" << PoolRim.Circumference() << endl;
cout << "甬道的面积是:" << PoolRim.Area() - Pool.Area() << endl;
}
#include <iostream>
#include <vector>
using namespace std;
int add(int a, int b)
{
return a + b;
}
add(88, 99) = 99;//错误,此处不能做左值
int g1;
int* Test()
{
return &g1;
}
Test() = NULL;//错误,此处不可做左值
*Test() = 666;//正确,降级后可做左值
int ga[] = { 8,9,1,1,2,3,4,5,6 };
int& at(int n)
{
return ga[n];
}
at(6) = 666;//正确,此处可做左值
vector<int> myvector(10, 8);
size_t nSize = myvector.size();
for (unsigned i = 0; i < nSize; i++)
myvector.at(i) = i;//正确,at()函数可做左值
3.3 vector 类成员函数演示
1.
- int n = (int) myvector.size();//c语言形式,myvector.size()返回值是long long类型,需要强制转换
- int m = int(myvector.size());//c++形式
- int m1(myvector.size());//c++形式
2.
//输出结果:10 20 0 100 0
int main()
{
std::vector<int> myvector(5);
int* p = myvector.data();
*p = 10;
++p;
*p = 20;
p[2] = 100;
std::cout << "myvector contains:";
for (unsigned i = 0; i < myvector.size(); ++i)
std::cout << ' ' << myvector.at(i);
std::cout << '\n';
return 0;
}
3.4 试图用vector开发项目
1.头文件main.h中一般不放using namespace std;
2.声明放在头文件中,声明可以重复,定义不能重复
4.2 视频末尾的
自行csdn中学习typedef函数指针
Day4
4.4 class关键字与权限管理
重载函数:overload-function
a)相同的区域内,同名函数,参数不同(个数和种类)。
b)例如:两个类内有相同名字的函数不是重载。
c)同在全局区或者同一类内相同名字不同参数就是重载。
d)它是今后泛型语法起源,C++模板技术的内部原理就是重载的继续升级。
struct默认所有成员都是public,class默认所有成员都是私有的。
Day 5
5.1 pass
5.2 5.3复杂类对象之间功能相互调用,很难,已pass,需要多回顾
5.4 static
请列出static关键字有哪些作用?
C语言有两种:修饰全局变量(函数)和修饰局部变量。
C++还有两种:修饰成员变量和成员函数。
面试题:在C语言中,static关键字的作用有哪些?
a)在一个函数前加上static关键字修饰之后,这个函数将禁止被跨文件访问,只限于在当前源文件中使用;
b)在一个全局变量的定义前加上 static修饰之后,这个全局变量也将被禁止跨文件访问,只限于在当前源文件中使用;
c)如果一个全局变量或函数不加static修饰时,在整个软件工程中只能有一份同名的全局变量或函数,否则在编译时将出现连接错误;
d)如果一个全局变量或函数加了static修饰之后,每一个源文件中都可以有一份同名的全局变量或函数,而编译时不会出现(同名冲突的)连接错误;
e)如果在一个函数内的局部变量前加上static修饰之后,这个变量已经不是纯粹的局部变量了。编译之后它与全局变量处于同一空间内,这个函数内的静态变量的生命期与全局变量相同,变量在程序进入main函数之前已经初始化完毕。
在C++语言中,static还有另外两个功能,就是修饰成员变量与成员函数。
1、静态成员函数:
a)普通成员函数中都有一个隐含的形参(this)
b)静态成员函数不含有this参数,静态成员函数是C格式函数(纯函数)
c)普通成员函数在调用时必须要用对象调用。
d)静态成员函数可以使用对象调用,也可以直接用类名调用。
e)静态成员函数跟对象无关,只是名义上划分给某个类(实质全局函数)。
对于静态成员函数,可以认为类名只是域名namespace
box::f1();
e)静态成员函数中不可以调用其他普通成员,只能调用本类或者其他类的静态成员。
f)普通成员函数可以调用静态成员(变量和函数)。
2、静态成员变量:
a)普通的成员变量,每定义一个类对象该成员变量都跟对象一起申请新的空间。
b)即静态数据成员在内存中只有一份空间,生存期为整个程序运行期。
c)在类内只是一个声明(无空间),静态数据成员必须在类体外进行定义和初始化。
d)静态成员变量在进入main函数之前已经执行了定义有了空间,而普通成员只有在对象定义时才有空间。
//test.cpp
#include<iostream>
using namespace std;
void Test()
{
cout << "测试" << endl;
}
//main.cpp
void Test();//声明
int main()
{
Test();//跨文件调用Test(),需要声明
}
//test.cpp
#include<iostream>
using namespace std;
static void Test()//static声明后,阻断隔壁的调用
{
cout << "测试" << endl;
}
//main.cpp
void Test();
int main()
{
Test();//此时无法调用
}
//test.cpp
#include<iostream>
using namespace std;
double g_d=888.88
//main.cpp
extern double g_d;//声明
int main()
{
g_d=999.99;//此时test.cpp中的g_d也变为999.99
}
//test.cpp
#include<iostream>
using namespace std;
static double g_d=888.88//static修饰后,隔壁无法调用
//main.cpp
extern double g_d;//声明
int main()
{
g_d=999.99;//错误,无法调用
}
应用:1.普通回调函数一般不可以放在类内作为成员函数,一般是定义为全局函数,加上static后的回调函数可以放在类内
2.跟对象无关的函数可以用static,名义上划分给某个类
Day 6
6.1 pass
6.2构造函数
构造函数(constructor):
a)构造函数是类的一种特殊成员函数,一般情况下,构造函数是专门用来初始化对成员变量的
,所以最好不要在构造函数中进行与对象的初始化无关的操作。
b)构造函数的函数名一定与类型完全相同,而且没有返回值(不是说返回值是void或者int,而是说不允许指定返回值)。
c)构造函数的返回值如果指定了任何类型都是错误,构造函数的功能是代替C语言对结构体对象初始化的大括号。
d)C语言对结构体成员初始化方式是使用大括号,如果该类(结构体)有构造函数就禁止使用大括号初始化成员数据。
#include <iostream>
using namespace std;
class Student
{
public:
const char* name;
int age;
float score;
};
int main()
{
Student s1 = { "小明",22,99 };//当成员变量是public时,可以用类似这样c语言风格的初始化
}
#include <iostream>
using namespace std;
class Student
{
public:
void set(const char* p, int a, float s)
{
name = p;
age = a;
score = s;
}
private:
const char* name;
int age;
float score;
};
int main()
{
Student s1 ;//当成员变量是private时,需要先定义对象,再调用共有接口去初始化
s1.set("小明", 22, 99);
}
#include <iostream>
using namespace std;
class Student
{
public:
Student(const char* p, int a, float s)
{
name = p;
age = a;
score = s;
}
private:
const char* name;
int age;
float score;
};
int main()
{
//C++98
Student s1("小明", 22, 99);//优化上一个方案,将定义对象和初始化结合为一步,用构造函数
//C++11
Student s1={"小明", 22, 99};
//C++11
Student s1{"小明", 22, 99};
}
2、构造函数调用,
a)是在定义对象时指定参数或者不指定参数,都自动调用构造函数。手工使用对象调用构造函数出错。
b)构造函数分为无参数,有参数和拷贝构造函数。定义了哪形式的构造函数,就意味着类有哪种对象定义方式。
c)使用=符号来调用构造函数,调用单参数的构造函数而且单参数类型和=符号右边的类型相同。
d)一般情况下=符号右边的类型没有适合单参数构造函数就不能使用=符号构造
e)只有一种类型不需要适合=符号右边构造函数。系统内部有缺省的拷贝构造函数,内部实现的是整体赋值。(还有一个缺省是operator=)
6.3 pass
Day 7
7.1 初始化列表起源
#include <iostream>
using namespace std;
class Student
{
public:
Student(const char* p, int a, float s)
{
name = p;//这里的语句是赋值语句,不是初始化语句
age = a;
score = s;
a = NULL;//这里的语句是赋值语句,不是初始化语句
}
private:
const char* name;
int age;
float score;
double* const a=NULL;//C++ 98不支持在这个地方初始化,而构造函数里是赋值语句不是初始化
//语句,然而指针常量要求必须初始化,该怎么办?
};
7.2 初始化列表
#include <iostream>
using namespace std;
class Student
{
public:
Student(const char* p, int a, float s) :a(NULL)//用初始化列表可以解决这个问题
{
name = p;//这里的语句是赋值语句,不是初始化语句
age = a;
score = s;
}
private:
const char* name;
int age;
float score;
double* const a;
};
1、必须初始化的变量类型:
a)常变量:const int n;//必须初始化
b)引用:int & m;//必须初始化
c)指针常量:int * const p;//必须初始化
d)构造函数有参数,没有无参数构造函数(default constructor)
2、以上三种必须初始化的变量放在类成员中怎么办?
a)使用C++11直接用等号或者大括号 const int m_age{99};
b)C++98要使用初始化列表 :
Student(const char* p, int a, float &f):m_age(a),m_fTest(f)
引用传值,可以等同于目标对象,直接a.
第四种:
成员对象必须传参的时候也要使用初始化列表完成。
3、初始化列表格式:
a)只能用于构造函数
b)冒号后面是成员变量,小括号内是右值
7.4 构造vector类
1.默认参数
#include <stdio.h>
//int add(int a, int b)
//{
// return a + b;
//}
//int add(int a, int b, int c)
//{
// return a + b + c;
//}
//把以上所有的函数合并成一个函数
int add(int a, int b, int c=0,int d=0)
{//注意点:就是必须从后往前默认 int add(int a=0, int b, int c=0,int d=0),这样是错误的
return a + b + c + d;
}
int main()
{
int n = add(88, 99);//至少2个实参
int m = add(88, 66, 77);
int d = add(88, 66, 77,-33);
//int x = add(8);//一个参数编译错误
return 0;
}
}
2.清零函数
#include <iostream>
using namespace std;
int main()
{
int a = int();
cout << a << endl;//a=0
}
Day 8
8.1 内联函数
1、inline函数简介:
a)有一道面试题,在C语言中如何实现inline函数?
b)类似于C语言的宏函数,不进出栈,速度快。
c)inline这个英文可以翻译成,在当前行内执行。
d)C++类成员函数中,如果是单行函数尽量把函数体放在头文件中。
编译器会自动加inline进行编译,加快程序运行速度。
e)内联函数不能太复杂,比如好几个循环,编译器内联不成功。
特点:就是速度比真正的函数速度块。
#include <iostream>
using namespace std;
inline int add(int a, int b)
{
return a + b;
}
//相当于c语言的宏函数
//#define add(a,b)(a+b);
int main()
{
int m = add(88, 99);
}
8.2 string类
构造函数的调用方法:
a)string s1 = s0;//98C++,只限于单参数构造
b)string s1(s,5);//98C++
c)string s1{s,5};//C++11推荐
d)string s1={s,5};//C++11
8.3 、C++致命性错误分析:以string为例
string s = "abc";
a)不能写入文件
fwrite(&s,szieof(s),1,pf);
b)发送给网络另一台电脑。
send和sendto
c)不可以memcpy和memset等操作
8.4析构函数
析构函数:
a)析构函数是对象销毁时自动调用函数;
b)栈对象析构函数发生的时间是离开函数时,被系统自动调用;
c)全局对象析构函数发生在什么时候?
全对象的构造发生在main函数进入之前,析构发生在main结束之后.
5、析构函数的作用:
a)不是所有类都必须要做析构函数?
比如:Admin类或者Worker类中没有指针变量,这种普通的类就不需要析构函数。
b)像vector,string这种类内部有指针,并且构造后会调用new。
这种类内部是需要析构函数清理运行过程new过的空间。
c)析构函数 释放的空间往往是指针指向的底层数据,结构体或者类内的空间是自动释放的。
Day 9
9.1过
9.2 9.3还需回顾
9.4
对于c
at()函数这里如果用中括号会错误
此时可以重载运算符中括号
此时就可以用中括号了
Day 10
10.1 10.2 pass