目錄
1、柔性數組:?
?2、友元函數:
3、靜態成員?
注意事項
面試題:c/c++ static的作用?
C語言:
C++:
為什么可以創建出?objx
4、對象與對象之間的關系
5、類模版
1、柔性數組:?
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>using namespace std;class MyString
{
private:struct StrNode{int refcount; //引用計數int slen;int capa;char data[0]; //數組不填或填0就成為柔性數組};private:StrNode* pstr;static const size_t DAFAUSIZE = 32;static const size_t INCSIZE = 2;static StrNode* GetMem(rsize_t n){size_t total = (n > DAFAUSIZE) ? n + 1 : DAFAUSIZE;StrNode* s = (StrNode*)malloc(sizeof(StrNode) + sizeof(char) * total);memset(s, 0, sizeof(StrNode) + sizeof(char) * total);s->capa = total - 1;return s;}static void FreeMem(StrNode *p){free(p);}
public:MyString(const char* p = nullptr) :pstr(nullptr){if (p != nullptr){int len = strlen(p);pstr = GetMem(len);pstr->refcount = 1;pstr->slen = len;strcpy(pstr->data, p);}}MyString(const MyString &st) :pstr(st.pstr) //st給當前對象{if (pstr != nullptr){pstr->refcount += 1; //+1 說明有兩個對象持有這塊空間}}MyString(MyString &&st) :pstr(st.pstr) //移動構造{st.pstr = nullptr;}~MyString() {if (pstr != nullptr && --pstr->refcount == 0){FreeMem(pstr);}pstr = nullptr;}ostream& operator<<(ostream& out)const{if (pstr != nullptr){out << pstr->data;}return out;}
};
ostream &operator<<(ostream &out, const MyString &st)
{return st << out;
}int main()
{MyString s1 = "chengxi";MyString s2(s1);MyString s3(s2);MyString s4(s3);cout << s3 << endl;return 0;
}
?2、友元函數:
(1)不具有傳遞特性、繼承特性、是單向的。
(2)友元函數分為:函數友元、成員函數友元、類友元
(3)友元函數是訪問類的對象非公有屬性。
成員函數友元:
using namespace std;
class Base;
class Test
{
private:int sum;
public:Test(int x = 0) :sum(x) {}void SetSum(int x = 0){sum = x;}int GetSum()const { return sum; }int Add(const Base &it);
};class Base
{friend int Test::Add(const Base& it);//成員函數友元int num;
public:Base(int x = 0) :num(x){}
};
int Test::Add(const Base& it)
{return this->sum + it.num;
}int main()
{Test t1(100);Base b1(2);t1.Add(b1);
}
類友元:?
using namespace std;
//Test對象訪問base的私有和公有,注意方向
class Base
{friend class Test;
private:int num;
public:Base(int x = 0) :num(x){}
};class Test
{
private:int sum;
public:Test(int x = 0) :sum(x) {}void SetSum(int x = 0){ sum = x;}int GetSum()const { return sum; }int Add(const Base &it) {return it.num + 10;}int func(const Base& it){return it.num;}
};int main()
{Test t1;Base b1;t1.Add(b1);t1.func(b1);return 0;
}
3、靜態成員?
(1) 類靜態成員只能在類外進行初始化,
(2)靜態成員變量在數據區存儲。靜態量不屬于對象,是被所有對象共享,不管有多少個對象,靜態成員只有一份存在于數據區。
(3)靜態數據可以在普通方法中使用
(4)為什么不能在參數列表中對靜態成員初始化?
答:參數列表,在定義對象的時候要調用構造函數,拿參數列表對數據成員進行創建,靜態成員被所有對象共享,在定義不同的對象時都要對靜態成員進行構建,c++中,數據成員(對象、變量)在生存期內只能被構建一次。放在參數列表中,被構建了n次,不允許。要在類外進行初始化。
靜態成員在類模版中,數據類型不同?,就會產生不同的 “靜態成員”
using namespace std;template<class T>
class Object
{
private:int value;
protected:static int num;
public:Object(int x=0):value(x){}~Object(){}
};class Test :public Object<Test>
{
public:Test(){cout << "Create Test::" << (num += 1) << endl;}
};class Base :public Object<Base>
{
public:Base() {cout << "Create Base:" << (num += 1) << endl;}
};
template<class T>
int Object<T>::num = 0;
int main() {Test t1[1];Base b1[2];return 0;
}
Test t1[1];
:創建一個包含 1 個?Test
?對象的數組,在創建?Test
?對象時,會調用?Test
?類的構造函數,輸出相應的信息。Base b1[2];
:創建一個包含 2 個?Base
?對象的數組,在創建?Base
?對象時,會調用?Base
?類的構造函數,輸出相應的信息。注意事項
由于?
Object
?類的靜態成員變量?num
?是模板化的,Object<Test>
?和?Object<Base>
?是不同的模板實例化,它們各自擁有獨立的?num
?副本。所以在創建?Test
?和?Base
?對象時,它們的?num
?計數是相互獨立的。
面試題
C語言:
(1)靜態關鍵字修飾全局/局部變量,存在于數據區,當函數消亡時,靜態變量還存在,可以&。
全局變量有static和無的區別?
(2)全局靜態變量只在本文件中可見,同一工程的其他文件不可見, (私有),未用static修飾的全局變量,可以用extern在其他文件用。
(3)static修飾函數,此函數只在當前文件夾有效,在其他文件中不能用,(私有)。修飾函數本身而不是修飾返回值 static int* add() {} ,。
C++:
(1)static可以修飾類的成員,要在類外進行初始化。所有的對象都共享同一個靜態成員變量,派生的類也共享(但前提是將其設置成
protected
?/public)。(2)靜態成員變量不屬于對象,無this,在常方法中可以修改靜態成員變量的值,this不修飾它。
static可以修飾屬性的類型,要在類外進行初始化,如果是靜態常性變量可以在類內進行初始化,但必須要求是整型類型。
(3)static修飾成員方法,static void func(){}? 無this指針。靜態成員方法無this。
(3)static修飾的成員方法可以訪問靜態屬性也可以訪問非靜態屬性(非靜態屬性必須把對象傳進來)。
靜態成員方法可以通過 對象訪問,也可以通過類名。
靜態成員變量
- 類的所有對象共享:靜態成員變量屬于類本身,而不是類的某個對象。無論創建多少個類的對象,靜態成員變量都只有一份副本,被所有對象共享。
- 需要在類外初始化:靜態成員變量必須在類外進行初始化,因為它不依賴于對象的創建。
?:obja可以創建出來,指針:4字節
#include<stdio.h>
#include<iostream>
using namespace std;
class Object
{
private:int value;
private:static Object objx;
private:Object(int x = 0) :value(x) {cout << "create Obj" << this << endl;}~Object(){cout << "destroy obj:" << this << endl;}
};
Object Object::objx(1);int main()
{return 0;
}
- 成員變量:
int value;
:一個私有成員變量,用于存儲對象的值。static Object objx;
:一個私有靜態成員變量,類型為?Object
?類本身。靜態成員變量屬于類,而不是類的某個對象,所有該類的對象共享同一個靜態成員變量。- 靜態成員變量初始化
Object Object::objx(1);
這行代碼對?
Object
?類的靜態成員變量?objx
?進行初始化,調用了?Object
?類的構造函數,并將參數?1
?傳遞給構造函數,將?value
?成員變量初始化為?1
。為什么可以創建出?
objx
雖然?
?Object
?類的構造函數和析構函數都是私有的,通常情況下,外部代碼無法直接創建?Object
?類的對象。但是,靜態成員變量?objx
?是類的一部分,類的內部可以訪問其私有成員。因此,在類的外部對靜態成員變量?objx
?進行初始化時,實際上是在類的作用域內調用了構造函數,這是被允許的。當程序開始執行時,在進入?
main
?函數之前,會先對靜態成員變量進行初始化,所以?Object::objx
?會被創建,調用構造函數輸出創建信息。當程序結束時,靜態對象?objx
?會被銷毀,調用析構函數輸出銷毀信息。
using namespace std;
class Object
{
private:int value;
private:static Object objx;
private:Object(int x = 0) :value(x) {cout << "create Obj" << this << endl;}~Object(){cout << "destroy obj:" << this << endl;}
public:void Print()const { cout << "value" << value << endl; }void SetValue(int x) { value = x; }int GetValue()const { return value; }//通過靜態方法將靜態對象的地址返回static Object* getObject(){return &objx;}
};
Object Object::objx(1);int main()
{Object* pa = Object::getObject();Object* pb = Object::getObject();if (pa == pb) { cout << "pa,pb pinter:object" << endl; }pa->Print();pa->SetValue(100);pa->GetValue();pa->Print();return 0;
}
if (pa == pb) { cout << "pa,pb pinter:object" << endl; }
:比較?pa
?和?pb
?的值,如果相等,說明它們指向同一個對象,輸出相應信息。由于?objx
?是靜態對象,無論調用多少次?getObject()
?函數,返回的都是同一個對象的地址,所以?pa
?和?pb
?相等。- 通過靜態成員函數可以在類外部訪問私有靜態成員對象,并且由于靜態成員對象只有一個實例,無論通過多少個指針訪問,操作的都是同一個對象。
4、對象與對象之間的關系
依賴關系:用-------> 表示
一個對象在運行期間會用到另一個對象的關系,通常在運行期間產生,并且伴隨運行時的變化依賴關系也發生變化。主要表現為 :“使用關系”。
關聯關系:用——> 表示:
靜態關系,如:學生和學校,是關聯關系
在設計中。關聯關系主要體現在目標類型的指針或引用。
聚合、繼承、組合等。
5、類模版
template<類型模版參數表>
類模板不是類,因此無法直接實例化對象,需要在聲明類時給定確定的數據類型,編譯器才會以此分配內存。對于普通類而言,類的聲明和類成員函數的定義可以寫在不同的文件中,但是對于類模板來說,最好定義在同一個文件中。
//define _N 10
template<class T,int N>
class SeqStack
{T* data;int capa;int top;static const int stackinitsize = 100;static const int incsize = 2;static T* GetMen(size_t sz){T* newdata = (T*)malloc(sizeof(T) * sz);if (nullptr == newdata){cout << "malloc fail" << endl;exit(1);}memset(newdata, 0, sizeof(T) * sz);return newdata;}static void FreeMem(T* p){free(p);}public:SeqStack(int sz = stackinitsize) :data(nullptr), capa(sz), top(-1){//data = (T*)malloc(sizeof(T) * capa); //只申請空間不構建對象data = GetMen(capa);}~SeqStack(){}int size()const { return top + 1; }bool empty()const { return size() == 0; }int capacity()const { return capa; }bool full()const { return size() == capacity(); }bool push(const T& x){if (full())return false; //滿了調增容函數 top += 1;new(&data[top]) T(x); //data[++top] = x;構建對象return true;}bool gettop(T *val) {if (empty())return false;val = data[top];return true;}bool poptop(T& val){if (empty())return false;val = data[top];(&data[top])->~T(); //析構top中的對象top -= 1;return true;}bool pop(){if (empty())return false;(&data[top])->T();top -= -1;return true;}};
int main()
{SeqStack<int, 10> istack; //using T:int N:10}
int main() {ClassName<int> intObj(10); // 實例化類模板,創建一個處理 int 類型的類對象int result = intObj.getData();std::cout << "Result: " << result << std::endl;ClassName<double> doubleObj(3.14); // 實例化類模板,創建一個處理 double 類型的類對象double dResult = doubleObj.getData();std::cout << "Result: " << dResult << std::endl;return 0;
}