C++筆記(4)

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函數了
6)查看類對象內存佈局,打開vs的命令提示符工具
E:\code\20180413\20180413>cl 20180413.cpp /d1reportSingleClassLayoutCGoodsInfo

7)普通成員變量和成員方法一定要依賴對象才能調用
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處,自動調用對象的析構函數
     */
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章