C++笔试题整理
1.new 、 、 malloc 、 free 關系
會調用對象的析構函數 , 和 new 對應 free 只會釋放內存, new 調用構造函數。 malloc 與 free 是 C++/C 語言的標準庫函數, new/ 是 C++ 的運算符。它們都可用于申請動態內存和釋放內存。對于非內部數據類型的對象而言,光用 maloc/free 無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。由于 malloc/free 是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加于 malloc/free 。因此 C++ 語言需要一個能完成動態內存分配和初始化工作的運算符 new ,以及一個能完成清理與釋放內存工作的運算符 。注意 new/ 不是庫函數。
總結:new和會自動調用對象的構造與析構函數而malloc與free不會;
new和式C++運算符,而malloc和free是C/C++標準庫函數。
——————————————————————————————–
2. 與 [] 區別
只會調用一次析構函數,而 [] 會調用每一個成員的析構函數。在 More Effective C++ 中有更為詳細的解釋:“當 操作符用于數組時,它為每個數組元素調用析構函數,然后調用 operator 來釋放內存。” 與 New 配套, [] 與 new [] 配套
MemTest*mTest1=newMemTest[10];
MemTest*mTest2=newMemTest;
int*pInt1=newint[10];
int*pInt2=newint;
[]pInt1; //-1-
[]pInt2; //-2-
[]mTest1;//-3-
[]mTest2;//-4-
在 -4- 處報錯。
這就說明:對于內建簡單數據類型, 和 [] 功能是相同的。對于自定義的復雜數據類型, 和 [] 不能互用。 [] 刪除一個數組, 刪除一個指針簡單來說,用 new 分配的內存用 刪除用 new[] 分配的內存用 [] 刪除 [] 會調用數組元素的析構函數。內部數據類型沒有析構函數,所以問題不大。如果你在用 時沒用括號, 就會認為指向的是單個對象,否則,它就會認為指向的是一個數組。
總結: 只會調用一次析構函數,而 [] 會調用每一個成員的析構函數。
——————————————————————————————–
3.C C++ JAVA 共同點,不同之處?
相同點:都是面向對象的語言
不同點:c/c++是編譯型語言,還有一些語言完全是解釋型的(如Basie),而java既是編譯型的又是解釋型的語言
c/c++存在指針運算,Basie沒有顯示指針,而java有指針,但取消了指針的運算
——————————————————————————————–
4. 繼承優缺點。
類繼承是在編譯時刻靜態定義的,且可直接使用,類繼承可以較方便地改變父類的實現。但是類繼承也有一些不足之處。首先,因為繼承在編譯時刻就定義了,所以無法在運行時刻改變從父類繼承的實現。更糟的是,父類通常至少定義了子類的部分行為,父類的任何改變都可能影響子類的行為。如果繼承下來的實現不適合解決新的問題,則父類必須重寫或被其他更適合的類替換。這種依賴關系限制了靈活性并最終限制了復用性。
——————————————————————————————–
5.C++ 有哪些性質(面向對象特點)
封裝,繼承和多態。
在面向對象程序設計語言中,封裝是利用可重用成分構造軟件系統的特性,它不僅支持系統的可重用性,而且還有利于提高系統的可擴充性;消息傳遞可以實現發送一個通用的消息而調用不同的方法;封裝是實現信息隱蔽的一種技術,其目的是使類的定義和實現分離。
——————————————————————————————–
6. 子類析構時要調用父類的析構函數嗎?
析構函數調用的次序是先派生類的析構后基類的析構,也就是說在基類的的析構調用的時候 , 派生類的信息已經全部銷毀了定義一個對象時先調用基類的構造函數、然后調用派生類的構造函數;析構的時候恰好相反:先調用派生類的析構函數、然后調用基類的析構函數 JAVA 無析構函數深拷貝和淺拷貝
——————————————————————————————–
7. 多態,虛函數,純虛函數
這么一大堆名詞,實際上就圍繞一件事展開,就是多態,其他三個名詞都是為實現C++的多態機制而提出的一些規則,下面分兩部分介紹,第一部分介紹【多態】,第二部分介紹【虛函數,純虛函數,抽象類】
一 【多態】
多態的概念 :關于多態,好幾種說法,好的壞的都有,分別說一下:
1 指同一個函數的多種形態。
個人認為這是一種高手中的高手喜歡的說法,對于一般開發人員是一種差的不能再差的概念,簡直是對人的誤導,然人很容易就靠到函數重載上了。
以下是個人認為解釋的比較好的兩種說法,意思大體相同:
2多態是具有表現多種形態的能力的特征,在OO中是指,語言具有根據對象的類型以不同方式處理之,特別是重載方法和繼承類這種形式的能力。
這種說法有點繞,仔細想想,這才是C++要告訴我們的。
3多態性是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之后,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。多態性在Object pascal和C++中都是通過虛函數(Virtual Function) 實現的。
這種說法看來是又易懂,又全面的一種,尤其是最后一句,直接點出了虛函數與多態性的關系,如果你還是不太懂,沒關系,再把3讀兩遍,有個印象,往后看吧。
- – - – - – - – - – - – - – - – - – - – - – - – - – - – - – -
二 【虛函數,純虛函數,抽象類】
多態才說了個概念,有什么用還沒說就進入第二部分了?看看概念3的最后一句,虛函數就是為多態而生的,多態的作用的介紹和虛函數簡直關系太大了,就放一起說吧。
多態的作用:繼承是子類使用父類的方法,而多態則是父類使用子類的方法。這是一句大白話,多態從用法上就是要用父類(確切的說是父類的對象名)去調用子類的方法,例如:
【例一】
class A {
public:
A() {}
(virtual) void print() {
cout << “This is A.” << endl;
}
};
class B : public A {
public:
B() {}
void print() {
cout << “This is B.” << endl; } }; int main(int argc, char* argv[]) { B b; A a; a = b;a.print;—————————————- make1 // A &a = b; a->print();———————————-make2
//A *a = new B();a->print();——————————–make3
return 0;
}
這將顯示:
This is B.
如果把virtual去掉,將顯示:
This is A.
(make1,2,3分別是對應兼容規則(后面介紹)的三種方式,調用結果是一樣的)
加上virtual ,多態了,B中的print被調用了,也就是可以實現父類使用子類的方法。
對多態的作用有一個初步的認識了之后,再提出更官方,也是更準確的對多態作用的描述:
多態性使得能夠利用同一類(基類)類型的指針來引用不同類的對象,以及根據所引用對象的不同,以不同的方式執行相同的操作。把不同的子類對象都當作父類來看,可以屏蔽不同子類對象之間的差異,寫出通用的代碼,做出通用的編程,以適應需求的不斷變化。賦值之后,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作(也就是可以調用子對象中對父對象的相關函數的改進方法)。
那么上面例子中為什么去掉virtual就調用的不是B中的方法了呢,明明把B的對象賦給指針a了啊,是因為C++定義了一組對象賦值的兼容規則,就是指在公有派生的情況下,對于某些場合,一個派生類的對象可以作為基類對象來使用,具體來說,就是下面三種情形:
Class A ;
class B:public A
1. 派生的對象可以賦給基類的對象
A a;
B b;
a = b;
2. 派生的對象可以初始化基類的引用
B b;
A &a = b;
3. 派生的對象的地址可以賦給指向基類的指針
B b;
A *a = &b;
或
A *a = new B();
由上述對象賦值兼容規則可知,一個基類的對象可兼容派生類的對象,一個基類的指針可指向派生類的對象,一個基類的引用可引用派生類的對象,于是對于通過基類的對象指針(或引用)對成員函數的調用,編譯時無法確定對象的類,而只是在運行時才能確定并由此確定調用哪個類中的成員函數。
看看剛才的例子,根據兼容規則,B的對象根本就被當成了A的對象來使用,難怪B的方法不能被調用。
【例二】
#include
using namespace std;
class A
{
public:
void (virtual) print(){cout << “A print”<</p>
private:
};
class B : public A
{
public:
void print(){cout << “B print”< private:
};
void test(A &tmpClass)
{
tmpClass.print();
}
int main(void)
{
B b;
test(b);
get);
return 0;
}
這將顯示:
B print
如果把virtual去掉,將顯示:
A print
那么,為什么加了一個virtual以后就達到調用的目的了呢,多態了嘛~那么為什么加上virtual就多態了呢,我們還要介紹一個概念:聯編
函數的聯編:在編譯或運行將函數調用與相應的函數體連接在一起的過程。
1 先期聯編或靜態聯編:在編譯時就能進行函數聯編稱為先期聯編或靜態聯編。
2 遲后聯編或動態聯編:在運行時才能進行的聯編稱為遲后聯編或動態聯編。
那么聯編與虛函數有什么關系呢,當然,造成上面例子中的矛盾的原因就是代碼的聯編過程采用了先期聯編,使得編譯時系統無法確定究竟應該調用基類中的函數還是應該調用派生類中的函數,要是能夠采用上面說的遲后聯編就好了,可以在運行時再判斷到底是哪個對象,所以,virtual關鍵字的作用就是提示編譯器進行遲后聯編,告訴連接過程:“我是個虛的,先不要連接我,等運行時再說吧”。
那么為什么連接的時候就知道到底是哪個對象了呢,這就引出虛函數的原理了:當編譯器遇到virtual后,會為所在的類構造一個表和一個指針,那個表叫做vtbl,每個類都有自己的vtbl,vtbl的作用就是保存自己類中虛函數的地址,我們可以把vtbl形象地看成一個數組,這個數組的每個元素存放的就是虛函數的地址.指針叫做vptr,指向那個表。而這個指針保存在相應的對象當中,也就是說只有創建了對象以后才能找到相應虛函數的地址。
【注意】
1為確保運行時的多態定義的基類與派生類的虛函數不僅函數名要相同,其返回值及參數都必須相同,否則即使加上了virtual,系統也不進行遲后聯編。
2 虛函數關系通過繼承關系自動傳遞給基類中同名的函數,也就是上例中如果A中print有virtual,那么 B中的print即使不加virtual,也被自動認為是虛函數。
*3 沒有繼承關系,多態機制沒有意義,繼承必須是公有繼承。
*4現實中,遠不只我舉的這兩個例子,但是大的原則都是我前面說到的“如果發現一個函數需要在派生類里有不同的表現,那么它就應該是虛的”。這句話也可以反過來說:“如果你發現基類提供了虛函數,那么你最好override它”。
純虛函數:
虛函數的作用是為了實現對基類與派生類中的虛函數成員的遲后聯編,而純虛函數是表明不具體實現的虛函數成員,即純虛函數無實現代碼。其作用僅僅是為其派生類提過一個統一的構架,具體實現在派生類中給出。
一個函數聲明為純虛后,純虛函數的意思是:我是一個抽象類!不要把我實例化!純虛函數用來規范派生類的行為,實際上就是所謂的“接口”。它告訴使用者,我的派生類都會有這個函數。
抽象類:
含有一個或多個純虛函數的類稱為抽象類。
【例三】
#include
using namespace std;
class A
{
public:
virtual float print() = 0;
protected:
float h,w;
private:
};
class B : public A
{
public:
B(float h0,float w0){h = h0;w = w0;}
float print(){return h*w;}
private:
};
class C : public A
{
public:
C(float h0,float w0){h = h0;w = w0;}
float print(){return h*w/2;}
private:
};
int main(void)
{
A *a1,*a2;
B b(1,2);
C c(1,2);
a1 = &b;
a2 = &c;
cout << a1->print()print就不能用了),給多態性造成不便,這里要強調的是,我們是希望用基類的指針調用派生類的方法,希望用到多態機制,如果讀者并不想用基類指針,認為用b,c指針直接調用更好,那純虛函數就沒有意義了,多態也就沒有意義了,了解一下多態的好處,再決定是否用純虛函數吧。
【注意】
1 抽象類并不能直接定義對象,只可以如上例那樣聲明指針,用來指向基類派生的子類的對象,上例中的A *a1,*a2;該為 A a1,a2;是錯誤的。
2 從一個抽象類派生的類必須提供純虛函數的代碼實現或依舊指明其為派生類,否則是錯誤的。
3 當一個類打算被用作其它類的基類時,它的析構函數必須是虛的。
【例三】
class A
{
public:
A() { ptra_ = new char[10];}
~A() { [] ptra_;} // 非虛析構函數
private:
char * ptra_;
};
class B: public A
{
public:
B() { ptrb_ = new char[20];}
~B() { [] ptrb_;}
private:
char * ptrb_;
};
void foo()
{
A * a = new B;
a;
}
在這個例子中,程序也許不會象你想象的那樣運行,在執行 a的時候,實際上只有A::~A()被調用了,而B類的析構函數并沒有被調用!這是否有點兒可怕? 如果將上面A::~A()改為virtual,就可以保證B::~B()也在 a的時候被調用了。因此基類的析構函數都必須是virtual的。純虛的析構函數并沒有什么作用,是虛的就夠了。通常只有在希望將一個類變成抽象類(不能實例化的類),而這個類又沒有合適的函數可以被純虛化的時候,可以使用純虛的析構函數來達到目的。
最后通過一個例子說明一下抽象類,純虛函數以及多態的妙用吧:
我們希望通過一個方法得到不同圖形面積的和的方式:
#include
using namespace std;
class A //定義一個抽象類,用來求圖形面積
{
public:
virtual float area() = 0;//定義一個計算面積的純虛函數,圖形沒確定,當
//不能確定具體實現
protected:
float h,w; //這里假設所有圖形的面積都可以用h和w兩個元素計算得出
//就假設為高和長吧
private:
};
class B : public A //定義一個求長方形面積的類
{
public:
B(float h0,float w0){h = h0;w = w0;}
float area (){return h*w;}//基類純虛函數的具體實現
private:
};
class C : public A //定義一個求三角形面積的類
{
public:
C(float h0,float w0){h = h0;w = w0;}
float area (){return h*w/2;}//基類純虛函數的具體實現
private:
};
float getTotal(A *s[],int n)//通過一個數組傳遞所有的圖形對象
//多態的好處出來了吧,不是多態,不能用基類A調用
//參數類型怎么寫,要是有100個不同的圖形,怎么傳遞
{
float sum = 0;
for(int i = 0;i < n; i++) sum = sum + s[i]->area();
return sum;
}
int main(void)
{
float totalArea;
A *a[2];
a[0] = new B(1,2); //一個長方形對象
a[1] = new C(1,2);//一個三角形對象
totalArea = getTotal(a , 2);//求出兩個對象的面積和
get);
return 0;
}
——————————————————————————————–
8. 求下面函數的返回值(微軟)
int func(x)
{
int countx = 0;
while(x)
{
countx ++;
x = x&(x-1);
}
return countx;
}
假定 x = 9999 。 答案: 8
思路:將 x 轉化為 2 進制,看含有的 1 的個數。
——————————————————————————————–
9. 什么是 “ 引用 ” ?申明和使用 “ 引用 ” 要注意哪些問題?
答:引用就是某個目標變量的 “ 別名 ”(alias) ,對應用的操作與對變量直接操作效果完全相同。申明一個引用的時候,切記要對其進行初始化。引用聲明完畢后,相當于目標變量名有兩個名稱,即該目標原名稱和引用名,不能再把該引用名作為其他變量名的別名。聲明一個引用,不是新定義了一個變量,它只表示該引用名是目標變量名的一個別名,它本身不是一種數據類型,因此引用本身不占存儲單元,系統也不給引用分配存儲單元。不能建立數組的引用。
——————————————————————————————–
10. 將 “ 引用 ” 作為函數參數有哪些特點?
( 1 )傳遞引用給函數與傳遞指針的效果是一樣的。這時,被調函數的形參就成為原來主調函數中的實參變量或對象的一個別名來使用,所以在被調函數中對形參變量的操作就是對其相應的目標對象(在主調函數中)的操作。
( 2 )使用引用傳遞函數的參數,在內存中并沒有產生實參的副本,它是直接對實參操作;而使用一般變量傳遞函數的參數,當發生函數調用時,需要給形參分配存儲單元,形參變量是實參變量的副本;如果傳遞的是對象,還將調用拷貝構造函數。因此,當參數傳遞的數據較大時,用引用比用一般變量傳遞參數的效率和所占空間都好。
( 3 )使用指針作為函數的參數雖然也能達到與使用引用的效果,但是,在被調函數中同樣要給形參分配存儲單元,且需要重復使用 “* 指針變量名 ” 的形式進行運算,這很容易產生錯誤且程序的閱讀性較差;另一方面,在主調函數的調用點處,必須用變量的地址作為實參。而引用更容易使用,更清晰。
——————————————————————————————–
11. 在什么時候需要使用 “ 常引用 ” ?
如果既要利用引用提高程序的效率,又要保護傳遞給函數的數據不在函數中被改變,就應使用常引用。常引用聲明方式: const 類型標識符 & 引用名 = 目標變量名;
例 1
int a ;
const int &ra=a;
ra=1; // 錯誤
a=1; // 正確
例 2
string foo( );
void bar(string & s);
那么下面的表達式將是非法的:
bar(foo( ));
bar(“hello world”);
原因在于 foo( ) 和 “hello world” 串都會產生一個臨時對象,而在 C++ 中,這些臨時對象都是 const 類型的。因此上面的表達式就是試圖將一個 const 類型的對象轉換為非 const 類型,這是非法的。引用型參數應該在能被定義為 const 的情況下,盡量定義為 const 。
——————————————————————————————–
12. 將 “ 引用 ” 作為函數返回值類型的格式、好處和需要遵守的規則 ?
格式:類型標識符 & 函數名(形參列表及類型說明) { // 函數體 }
好處:在內存中不產生被返回值的副本;(注意:正是因為這點原因,所以返回一個局部變量的引用是不可取的。因為隨著該局部變量生存期的結束,相應的引用也會失效,產生 runtime error! 注意事項:
( 1 )不能返回局部變量的引用。這條可以參照 Effective C++[1] 的 Item 31 。主要原因是局部變量會在函數返回后被銷毀,因此被返回的引用就成為了 ” 無所指 ” 的引用,程序會進入未知狀態。
( 2 )不能返回函數內部 new 分配的內存的引用。這條可以參照 Effective C++[1] 的 Item 31 。雖然不存在局部變量的被動銷毀問題,可對于這種情況(返回函數內部 new 分配內存的引用),又面臨其它尷尬局面。例如,被函數返回的引用只是作為一個臨時變量出現,而沒有被賦予一個實際的變量,那么這個引用所指向的空間(由 new 分配)就無法釋放,造成 memory leak 。
( 3 )可以返回類成員的引用,但最好是 const 。這條原則可以參照 Effective C++[1] 的 Item 30 。主要原因是當對象的屬性是與某種業務規則( business rule )相關聯的時候,其賦值常常與某些其它屬性或者對象的狀態有關,因此有必要將賦值操作封裝在一個業務規則當中。如果其它對象可以獲得該屬性的非常量引用(或指針),那么對該屬性的單純賦值就會破壞業務規則的完整性。
( 4 )流操作符重載返回值申明為 “ 引用 ” 的作用:
流操作符 << 和 >> ,這兩個操作符常常希望被連續使用,例如: cout << “hello” << endl; 因此這兩個操作符的返回值應該是一個仍然支持這兩個操作符的流引用。可選的其它方案包括:返回一個流對象和返回一個流對象指針。但是對于返回一個流對象,程序必須重新(拷貝)構造一個新的流對象,也就是說,連續的兩個 << 操作符實際上是針對不同對象的!這無法讓人接受。對于返回一個流指針則不能連續使用 << 操作符。因此,返回一個流對象引用是惟一選擇。這個唯一選擇很關鍵,它說明了引用的重要性以及無可替代性,也許這就是 C++ 語言中引入引用這個概念的原因吧。 賦值操作符 = 。這個操作符象流操作符一樣,是可以連續使用的,例如: x = j = 10; 或者 (x=10)=100; 賦值操作符的返回值必須是一個左值,以便可以被繼續賦值。因此引用成了這個操作符的惟一返回值選擇。
例 3
# i nclude
int &put(int n);
int vals[10];
int error=-1;
void main()
{
put(0)=10; // 以 put(0) 函數值作為左值,等價于 vals[0]=10;
put(9)=20; // 以 put(9) 函數值作為左值,等價于 vals[9]=20;
cout< cout<=0 && n else { cout< 6′) : puts(” return 0;
}
——————————————————————————————–
114. 交換兩個數的宏定義
交換兩個參數值的 宏定義 為: . #define SWAp (a,b) (a)=(a)+(b);(b)=(a)-(b);(a)=(a)-(b);
——————————————————————————————–
115.Itearator 各指針的區別
游標和指針
我說過游標是指針,但不僅僅是指針。游標和指針很像,功能很像指針,但是實際上,游標是通過重載一元的 ”*” 和 ”->” 來從容器中間接地返回一個值。將這些值存儲在容器中并不是一個好主意,因為每當一個新值添加到容器中或者有一個值從容器中刪除,這些值就會失效。在某種程度上,游標可以看作是句柄( handle )。通常情況下游標( iterator )的類型可以有所變化,這樣容器也會有幾種不同方式的轉變:
iterator—— 對于除了 vector 以外的其他任何容器,你可以通過這種游標在一次操作中在容器中朝向前的方向走一步。這意味著對于這種游標你只能使用 “++” 操作符。而不能使用 “–” 或 “+=” 操作符。而對于 vector 這一種容器,你可以使用 “+=” 、 “—” 、 “++” 、 “-=” 中的任何一種操作符和 “” 、 “>=” 、 “==” 、 “!=” 等比較運算符。
——————————————————————————————–
116. C++ 中的 class 和 struct 的區別
從語法上,在 C++ 中(只討論 C++ 中)。 class 和 struct 做類型定義時只有兩點區別:
(一)默認繼承權限。如果不明確指定,來自 class 的繼承按照 private 繼承處理,來自 struct 的繼承按照 public 繼承處理;
(二)成員的默認訪問權限。 class 的成員默認是 private 權限, struct 默認是 public 權限。
除了這兩點, class 和 struct 基本就是一個東西。語法上沒有任何其它區別。
不能因為學過 C 就總覺得連 C++ 中 struct 和 class 都區別很大,下面列舉的說明可能比較無聊,因為 struct 和 class 本來就是基本一樣的東西,無需多說。但這些說明可能有助于澄清一些常見的關于 struct 和 class 的錯誤認識:
( 1 )都可以有成員函數;包括各類構造函數,析構函數,重載的運算符,友元類,友元結構,友元函數,虛函數,純虛函數,靜態函數;
( 2 )都可以有一大堆 public/private/protected 修飾符在里邊;
( 3 )雖然這種風格不再被提倡,但語法上二者都可以使用大括號的方式初始化:
A a = {1, 2, 3}; 不管 A 是個 struct 還是個 class ,前提是這個類 / 結構足夠簡單,比如所有的成員都是 public 的,所有的成員都是簡單類型,沒有顯式聲明的構造函數。
( 4 )都可以進行復雜的繼承甚至多重繼承,一個 struct 可以繼承自一個 class ,反之亦可;一個 struct 可以同時繼承 5 個 class 和 5 個 struct ,雖然這樣做不太好。
( 5 )如果說 class 的設計需要注意 OO 的原則和風格,那么沒任何理由說設計 struct 就不需要注意。
( 6 )再次說明,以上所有說法都是指在 C++ 語言中,至于在 C 里的情況, C 里是根本沒有 “class” ,而 C 的 struct 從根本上也只是個包裝數據的語法機制。
—————————————————————
最后,作為語言的兩個關鍵字,除去定義類型時有上述區別之外,另外還有一點點: “class” 這個關鍵字還用于定義模板參數,就像 “typename” 。但關鍵字 “struct” 不用于定義模板參數。
在模版中,類型參數前面可以使用class或typename,如果使用struct,則含義不同,struct后面跟的是“non-type template parameter”,而class或typename后面跟的是類型參數。
template
void f(X x)
{
}
//出錯信息:d:codecpptestcpptestcpptest.cpp(33) : error C2065: ‘X’ : undeclared identifier
關于使用大括號初始化
class 和 struct 如果定義了構造函數的話,都不能用大括號進行初始化
如果沒有定義構造函數, struct 可以用大括號初始化。
如果沒有定義構造函數,且所有成員變量全是 public 的話,可以用大括號初始化。
關于默認訪問權限
class 中默認的成員訪問權限是 private 的,而 struct 中則是 public 的。
關于繼承方式
class 繼承默認是 private 繼承,而 struct 繼承默認是 public 繼承。
關于模版
在模版中,類型參數前面可以使用 class 或 typename ,如果使用 struct ,則含義不同, struct 后面跟的是 “non-type template parameter” ,而 class 或 typename 后面跟的是類型參數。
class 中有個默認的 this 指針, struct 沒有
不同點:構造函數,析構函數 this 指針
——————————————————————————————–
117. 有關重載函數
返回值類型不同構不成重載
參數參數順序不同能構成重載
c++ 函數同名不同返回值不算重載!函數重載是忽略返回值類型的。
成員函數被重載的特征有:
1) 相同的范圍(在同一個類中);
2) 函數名字相同;
3) 參數不同;
4) virtual 關鍵字可有可無。
5) 成員函數中 有無 const ( 函數后面 ) 也可判斷是否重載
——————————————————————————————–
118. 數據庫與 T-SQL 語言
關系數據庫是表的集合,它是由一個或多個關系模式定義。 SQL 語言中的數據定義功能包括對數據庫、基本表、視圖、索引的定義。
——————————————————————————————–
119. 關系模型的基本概念
關系數據庫以關系模型為基礎,它有以下三部分組成:
● 數據結構 —— 模型所操作的對象、類型的集合
● 完整性規則 —— 保證數據有效、正確的約束條件
● 數據操作 —— 對模型對象所允許執行的操作方式
關系( Relation )是一個由行和列組成的二維表格,表中的每一行是一條記錄( Record ),每一列是記錄的一個字段( Field )。表中的每一條記錄必須是互斥的,字段的值必須具有原子性。
——————————————————————————————–
120.SQL 語言概述
SQL (結構化查詢語言)是關系數據庫語言的一種國際標準,它是一種非過程化的語言。通過編寫 SQL ,我們可以實現對關系數據庫的全部操作。
● 數據定義語言( DDL ) —— 建立和管理數據庫對象
● 數據操縱語言( DML ) —— 用來查詢與更新數據
● 數據控制語言( DCL ) —— 控制數據的安全性
起來是一個很簡單的問題,每一個使用過 RDBMS 的人都會有一個概念。
事務處理系統的典型特點是具備 ACID 特征。 ACID 指的是 Atomic (原子的)、 Consistent (一致的)、 Isolated (隔離的)以及 Durable (持續的),它們代表著事務處理應該具備的四個特征:
原子性:組成事務處理的語句形成了一個邏輯單元,不能只執行其中的一部分
一致性:在事務處理執行之前和之后,數據是一致的。
隔離性:一個事務處理對另一個事務處理沒有影響。
持續性:當事務處理成功執行到結束的時候,其效果在數據庫中被永久紀錄下來。
——————————————————————————————–
121.C 語言中結構化程序設計的三種基本控制結構
順序結構
選擇結構
循環結構
——————————————————————————————–
122.CVS 是什么
cvs ( Concurrent Version System ) 是一個版本控制系統。使用它,可以記錄下你的源文件的歷史。
例如,修改軟件時可能會不知不覺混進一些 bug ,而且可能過了很久你才會察覺到它們的存在。有了 cvs ,你可以很容易地恢復舊版本,并從中看出到底是哪個修改導致了這個 bug 。有時這是很有用的。
CVS 服務器端對每個文件維護著一個修訂號 , 每次對文件的更新,都會使得文件的修訂號加 1 。在客戶端中也對每個文件維護著一個修訂號 ,CVS 通過這兩個修訂號的關系,來進行 Update,Commit 和發現沖突等操作操作
——————————————————————————————–
123. 三種基本的數據模型
按照數據結構類型的不同,將數據模型劃分為層次模型、網狀模型和關系模型。
——————————————————————————————–
總結
- 上一篇: 万有引力的意思_万有引力的本质是什么?
- 下一篇: DNS到底是干什么用的