1.通过引用的一些了解,得到以下结论:
结论一:
引用必须初始化;初始化的值一定是能取地址的。
int main(int argc,char *argv[])
{
int &b=a;//&必须和变量名连接,此处是引用初始化
int *&p2=(int *)0x100;// xx 指针的引用,0x100是常量,不能取地址
}
结论二:
普通的引用变量不能引用常量;如果要引用,必须得用常引用才能引用常量(因为对立即数产生了临时量)
//int &a=20;//xx普通的引用变量引用了常量
const int &a=20;
/*
const int temp = 20;
const int &a = temp;
*/
//int *&p2=(int *)0x100;//xx普通的指针引用常量引用了指针常量
int *const &p2=(int *)0x100;
/*
int *const ptemp = (int*)0x100;
int *const &p2 = ptemp;
*/
结论三:
常引用和const指针才能引用或指向常量。
const int a=10;//常量
int &b=a;//false-->const int &b=a;//true 常引用
int *p=&a;//false-->const int *p=&a;//true const指针
2.补充类型转换问题:
int a=10;
int *p=&a;
const int *&q=p;
||
const int **q=&p;//const int ** int **//false
int a=10;
const int *p=a;
int *&q=p;
||
int **q=&p;//int ** const int **//false
3.C/C++中的动态内存开辟:
C:malloc/free;
(1)malloc和free是函数(libc.so C语言的库函数)
int *p1=(int *)malloc(sizeof(int));//(int *)对(void *)进行强转
free(p1);
(2)free释放内存的时候,不区分释放的是单个元素内存还是数组内存
int **p2=(int **)malloc(sizeof(int *)*3);//存放3个整型指针
for(int i=0;i<3;++i)
{
p2[i]=(int *)malloc(sizeof(int)*4);//每个指针的字节大小为4
}
for(int i=3;i<3;++i)
{
free(p2[i]);//从二维开始释放
}
free(p2);
(3)malloc开辟内存失败,返回值和NULL进行判断
int *p=(int *)malloc(sizeof(int));
if(NULL==p){return NULL;}
C++:new/delete
(1)new和delete属于运算符,不属于函数
int *p1=new int;
int *p2=new int(10);/开辟内存并初始化
(2)delete释放内存的时候,区分释放的是单个元素内存还是数组内存
int **p2=new int *[3];//开辟3个整型数组
for(int i=0;i<3;++i)
{
p2[i]=new int [4];//数组里存放整形元素/数据
}
for(int i=0;i<3;++i)
{
delete[]p2[i];//开辟时有[],delete就加上[]
}
delete[]p2;
(3)new开辟内存失败,抛出bad_alloc异常
try
{
int *p1=new int;
}
catch(const bad_alloc &err)
{
cout<<"new失败"<<endl;
}
面试问题:
一.以下动态开辟有何区别?
int *p=new int [3];//在堆上开辟了三个元素,这三个元素的值为随机值
int *p=new int [3]();//在堆上开辟了三个元素并初始化,这三个元素的值默认初始化为0
二.new和malloc有何区别?
1)malloc是函数,而new是运算符;
2)malloc结果要进行类型强转,而new不用强转;
3)malloc只能开辟内存,new不仅能开辟内存还能初始化;
4)malloc开辟失败返回NULL指针,new开辟内存失败抛出bad_alloc异常;
5)new底层调用的也是malloc。
三.delete和free有何区别?
1)delete底层调用的也是free来释放内存的;
2)free释放内存的时候,不区分释放的是单个元素内存还是数组内存;delete释放内存的时候,区分释放的是单个元素内存还是数组内存,因为delete和指针之间需要添加一个[]来表示释放的是数组内存(开辟时候有[]时就添加[])。
eg:
开辟了一个3行4列的二维数组,每个元素放的都是一个字符串“aaa”,“bbb”等,给每一个元素都初始化成“hello world”,最终并释放掉。
char ***p = new char**[3];
for (int i = 0; i < 3; ++i)
{
p[i] = new char*[4];
for (int j = 0; j < 4; ++j)
{
p[i][j] = "hello world!";
}
}
for (int i = 0; i < 3; ++i)
{
delete[[]pi];
}
delete[]p;
4.名字空间作用域:namespace
C语言的作用域:全局作用域和局部作用域
C++的作用域:局部作用域,全局作用域和类作用域
namespace作用:解决全局作用域名字冲突的问题。
#include<iostream>
//在系统中已经存在名为std这样一个函数,里面已经定义了cout,cin或是endl等
using std::cout;
using std::endl;
//1)使用using声明后,main函数中就可以调用cout和endl了,但每次只能声明一次,过于麻烦
using namespace std;
/2)用using操作符后,就可以用std中任何被定义的变量或函数了,就很方便了
int main()
{
cout << " " << endl;
}
5.C++的类和对象
面试问题:
一.面向对象语言有什么四大特征?抽象,封装/隐藏,继承,多态
二.面向对象语言有什么三大特征?封装/隐藏,继承,多态
关系型数据库:SQL Server MySQL Oracle
数据库表中的关系:一对一,一对多,多对多
类的创建和表的创建一样:
(1)先看问题场景都有哪些实体(2)找实体的属性(3)找实体之间的关系
类之间的关系:组合,继承
类的访问限定符:public(公有的)
private(私有的)
protected(保护的)【在之后的继承中出现】
概念一:
1)创建类的目的,是来抽象实体的类型,从实体的属性和行为两方面,得到类的成员变量和成员方法,因为类是实体类型的抽象,所以类类型不占空间
2)用struct和class都可以定义类,不同的是,在没有访问限定符的情况下,class定义的类默认都是private访问限定,struct都是public访问限定
3)分析类类型字节大小的时候,和struct结构体的字节大小计算方式是一样的,都存在字节对齐的问题,唯一不同的,就是C语言的空struct,大小是0,而C++的空class,大小是1
4)类成员方法的定义,可以在类体内直接定义;也可以在类外去定义
方法在类外定义,一定要在方法名字之前,添加类的作用域
void CGoodsInfo::initGoods(char *n, int a, double p)
5)成员方法在类体内实现的话,自动处理成inline函数了
E:\code\20180413\20180413>cl 20180413.cpp /d1reportSingleClassLayoutCGoodsInfo
const int NAME_LEN = 20;//创建类的目的,是来抽象实体的类型
class CGoodsInfo
{
public:
//一般把实体的行为定义成公有的,称作成员方法/成员函数(指令,在.test段)
//在此声明,在类外定义
void initGoods(char *n, int a, double p);
void showGoods();
//提供一些getXXX和setXXX的方法,在类体内直接定义
void setName(char *n){ strcpy(name, n); }
void setAmount(int a){ amount = a; }
void setPrice(double p){ price = p; }
char* getName(){ return name; }
int getAmount(){ return amount; }
double getPrice(){ return price; }
private:
//一般把实体的属性都定义成私有的,称作成员变量(在栈上)
char name[NAME_LEN];
int amount;
double price;
};
//方法在类外定义,一定要在方法名字的前面,添加类的作用域
void CGoodsInfo::initGoods(char *n, int a, double p)
{
strcpy(name, n);
amount = a;
price = p;
}
void CGoodsInfo::showGoods()
{
cout << "name:" << name << endl;
cout << "amount:" << amount << endl;
cout << "price:" << price << endl;
}
int main()
{
//用类定义对象,也叫做类实例化了一个对象
CGoodsInfo good1;
//通过访问公有成员方法来访问私有成员变量
good1.initGoods("shangpin1", 100, 80.0);
good1.showGoods();
good1.setPrice(85.0);
good1.showGoods();
cout << good1.getName() << endl;
return 0;
}
6.顺序栈
对象的构造函数和析构函数:
构造函数:SqStack()==>void init() : 对对象进行初始化
析构函数:~SqStack()==>void relase() : 在对象内存释放之前,把占用的其他资源释放掉
/*
1)构造和析构函数的名字必须和类名一样,不能随便起
2)构造和析构函数没有返回值
3)构造函数可以任意带参数,构造函数是可以重载的;析构函数是不能带有参数的,因此析构函数只有一个。
*/
const int STACK_SIZE = 10;
class SqStack
{
public:
//顺序栈的初始化
void init();
//释放资源的代码
void relase();
//构造函数
SqStack()
{
cout << "SqStack()" << endl;
mtop = -1;
mpstack = new int[STACK_SIZE];
}
//构造函数
~SqStack()
{
cout << "~SqStack()" << endl;
delete[]mpstack;
}
//入栈操作
void push(int val);
//出栈操作
void pop();
//获取栈顶元素
int top();
//判断栈空
bool empty(){ return mtop == -1; }
//判断栈满
bool full(){ return mtop == STACK_SIZE - 1; }
private:
//int mstack[STACK_SIZE];//定义一个宏,在编译时就给了数组大小
int *mpstack;//用指针做成员变量,就无需在编译时就给大小
int mtop;
};
//顺序栈的初始化
void SqStack::init()
{
mtop = -1;
mpstack = new int[STACK_SIZE];
}
//释放资源的代码
void SqStack::relase()
{
delete[]mpstack;
}
//入栈操作
void SqStack::push(int val)
{
if (full())
return;
mpstack[++mtop] = val;
}
//出栈操作
void SqStack::pop()
{
if (empty())
return;
--mtop;
}
//获取栈顶元素
int SqStack::top()
{
if (empty())
throw "stack is empty!";
return mpstack[mtop];
}
int main()
{
/*
定义对象需要两步
1:给对象分配内存
2:给对象调用构造函数
*/
SqStack stack1; // stack[STACK_SIZE] top
//stack1.init();
stack1.push(10);
stack1.push(4);
stack1.push(56);
stack1.push(21);
stack1.push(9);
while (!stack1.empty())
{
int val = stack1.top();
cout << val << " ";
stack1.pop();
}
//stack1.relase();
SqStack stack2;
stack2.push(10);
stack2.push(4);
stack2.push(56);
return 0;
/*
栈上的对象,在return处,自动调用对象的析构函数
*/
}