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處,自動調用對象的析構函數
*/
}