拷贝构造,深度拷贝,关于delete和default相关的操作,explicit,类赋初值,构造函数和析构函数,成员函数和内联函数,关于内存存储,默认参数,静态函数和普通函数,const函数,友元
1.拷貝構造
//拷貝構造的規則,有兩種方式實現初始化。
//1、一個是通過在后面:a(x),b(y)的方式實現初始化。
//2、第二種初始化的方式是直接在構造方法里面實現初始化。
案例如下:
#include<iostream>//如果聲明已經定義,邊不會生成 class classA { private:int a;int b; public://拷貝構造的規則,有兩種方式實現初始化//1、一個是通過在后面:a(x),b(y)的方式實現初始化//2、第二種初始化的方式是直接在構造方法里面實現初始化classA(int x,int y)//:a(x),b(y){a = x;b = y;}void print(){std::cout << a << " " << b << std::endl;} };void main() {classA class1(10,100);//編譯器會默認生成默認的構造函數classA class2(class1);//編譯器會生成默認的拷貝構造函數class1.print();//默認的拷貝構造函數,說明可以通過類的方式實現淺拷貝class2.print();std::cin.get(); }
2.深度拷貝,使用深度拷貝的時候要將分配內存,這是其中的關鍵點。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include<string> class string { public:char *p;int length;string(int num, char *str){//獲取長度,分配內存,拷貝內容length = num;p = new char[length]; //深度拷貝的時候,要分配內存memset(p, 0, length);//strcpy(p, str);}string(const string & string1){this->p = new char[string1.length];this->length = string1.length;//將開辟的內存中的內容賦值為0memset(this->p, 0, this->length);strcpy(this->p, string1.p);}~string(){delete[] p;//刪除的時候要帶上[]} }; void main() {string *pstr1 = new string(10, "hello");std::cout << pstr1->p << std::endl;string *pstr2 = new string(*pstr1);delete pstr1;std::cout << pstr2->p << std::endl;std::cin.get(); }
上面的運行結果是:
void main() {string str1(10,"hello");std::cout << str1.p << std::endl;string str2(str1); //這里說明可以通過std::cout << str2.p << std::endl;std::cin.get(); }
運行結果如下:
3.關于delete和default相關的操作
A:delete可以禁用默認生成的函數,禁用構造可以無法實例化,禁用拷貝構造,可以實現禁止別人拷貝你。
B:default的作用是讓函數默認存在。
myclassA::myclassA(void); //嘗試引用已刪除的函數 myclassA() = delete; //默認刪除構造函數,無法實例化 myclassA(const myclassA &) = delete; //拷貝構造函數 myclassA(const myclassA &) = default;~myclassA();void main() {//myclassA myclassa1;//myclassA myclassa2(myclassa1);//myclassA myclassa3 = myclassa1; //重載了=,根據類型//myclassA a1; }
4.explicit.cpp
#include <iostream> #include <array>class classobj { public:int num; public://使用有參構造,使用explicitexplicit classobj(int data){this->num = data;std::cout << "被構造" << num << std::endl;}~classobj(){std::cout << "被銷毀" << num << std::endl;} protected: private: };void main() {//C 語言風格的數組,構造一個數組,銷毀一個數組classobj obj(0);//單獨獨有構造函數//C語言風格數組構造方式classobj objx[3] = { classobj(1), classobj(2), classobj(3) };classobj (*ppobjA)[3] = &objx; //指向數組的指針classobj *pobj(new classobj(4));classobj * ppobj[3];//數組,每一個元素都是指針ppobj[0] = new classobj(5);ppobj[1] = new classobj(6);ppobj[2] = new classobj(7);std::cin.get(); }
運行結果如下:
?
5.類的賦初值
第一種方式:? 在構造函數后面通過加上? :變量名(變量值)
第二種方式:在構造函數,函數體里面寫上?? 變量名=變量值;
第三種方式:類名對象名=變量值
#include <iostream> #include <array>class classobj { public:int num; public://使用有參構造,使用explicitclassobj(int data){this->num = data;std::cout << "被構造" << num << std::endl;}~classobj(){std::cout << "被銷毀" << num << std::endl;} protected: private: };void main() {classobj num = 5;//賦值號,類型轉換num = 6; //說明類的初始化可以通過等號的方式賦值classobj data(7);classobj obj(8); //創建對象必須合適的構造函數//C++風格數組的作用classobj *p = new classobj(9);std::array<classobj, 2> myarray = { obj, *p };std::cin.get(); }
運行結果是:
賦值案例2:
#include <iostream>class myclass { public:int num; public:myclass():num(4)//初始化第一種方式{//num = 10; //第二種方式}myclass(int data) //構造函數可以重載{std::cout << "class create by data: " << data << std::endl;num = data;}~myclass(){std::cout << "class delete";} };void run() {myclass myclass1(10);myclass myclass2 = 102;myclass *p = new myclass(103);myclass *p2(new myclass(104));std::cout << (*p).num << std::endl;//std::cout << myclass1.num << std::endl; };void main() {run();std::cin.get(); }
運行結果如下:
6.構造函數與析構函數
A:系統自動生成了構造函數與析構函數
B:被包含的,最先調用構造,最后調用析構
C:包含別人的,最后調用構造,最先調用析構
案例說明:
#include <iostream>//系統自動給你生成了構造函數與析構函數 //被包含的,最先分配,最后釋放(這里是調用析構不是釋放內存) //包含別人的,最后分配,最先釋放(這里是調用析構不是釋放內存)class fushu { public:fushu();~fushu(); };fushu::fushu() {std::cout << "fushu構建" << std::endl; }fushu::~fushu() {std::cout << "fushu銷毀" << std::endl; }class math { public:fushu fushu1;//一個類調用另外一個類math(){std::cout << "math構建" << std::endl;}~math(){std::cout << "math銷毀" << std::endl;} };void go() {math math1; }void main() {go();std::cin.get(); }
運行結果截圖:
分析,上面的math類調用fushu這個類,這個結果說明了A,B,C.
7.成員函數和內聯函數
A:內聯函數一般在頭文件中。
編寫頭文件:
#pragma once #include <iostream> class fushu { public:int x;int y; public:fushu();~fushu();void show();//顯示內聯inline void showall(int x, int y);//編譯器優化,默認隱式內聯void setxy(int x, int y);void show(int x,int y); };//內聯函數原則上放在頭文件,并且在實現內聯函數的時候,去掉inline標識符 //內聯函數需要展開,(VS2013是要求放在頭文件的) void fushu::showall(int x, int y) {std::cout << "頭文件中內聯函數showall:this->x = " <<(this->x = x) << "this->y =" <<(this->y = y) << std::endl; }
頭文件中的實現類
#include "fushu.h" //::這個符號卡面必須是類或者命名空間fushu::fushu() {std::cout << "對象被創建" << std::endl; }fushu::~fushu() {std::cout << "對象被銷毀" << std::endl; } //類調用成員函數,需要明確那個類的對象調用void fushu::show() {std::cout << "show" << std::endl; }void fushu::setxy(int x, int y)//編譯器優化,默認隱式內聯 {this->x = x;this->y = y;std::cout << "實現類中setxy:(this->x)= "<<(this->x)<< " (this->y)=" << (this->y) << std::endl; }void fushu::show(int x, int y) {std::cout << "實現類中show:(this->x)= " << (this->x) << " (this->y)=" << (this->y) << std::endl; }
調用函數:
#include<iostream> #include "fushu.h"void stackrun() {fushu fushu1;//對象在棧上fushu1.show(); }void heaprun() {fushu *pfushu = new fushu;//對象在堆上pfushu->show();pfushu->showall(10, 9);pfushu->setxy(19, 29);pfushu->show(1, 2);//內部成員函數重載,函數指針,明確了參數delete pfushu; }void main() {heaprun();std::cin.get(); }
7.關于內存
#include <iostream>class myclass { public:int num;int data;int *p;const int coint;//常量必須在構造函數中初始化int & myint; //引用必須初始化,在構造函數中初始化static int shu; //聲明,在外部進行初始化static const int dashu; public:static void go(){}void run(){}//常量,引用,必須重載構造函數初始化myclass(int a, int b) :myint(a), coint(b){//引用就是共用地址,常量新開辟備份機制std::cout << &a << " " << &b << std::endl;std::cout << &myint << " " << &coint << std::endl;const int *p = &coint;//地址std::cout << *p << " " << coint << std::endl;int *px = const_cast<int *>(p);//去掉const轉換*px = 12;std::cout << coint << " " << *px << std::endl;}~myclass(){} };//對于靜態的變量要在類外面初始化 int myclass::shu = 0; //對于靜態的變量要在類外面初始化 const int myclass::dashu = 20;void main() {const int *px = &(myclass::dashu);std::cout << px << std::endl;int *p = const_cast<int *>(px);//靜態常量區可以訪問,不可以修改,所以下面的方式是錯誤的//*p = 123;std::cout << *px << " " << *p << " " << myclass::dashu;std::cin.get(); }
運行結果是:
8.關于默認參數
#include<iostream>class goodclass { public:int num = 1;//默認初始化的值,C++11特定const int data = 90;//const,這種方式初始化就不需要寫構造函數了 public:static void show(goodclass good1){std::cout << good1.num << " " << good1.data << std::endl;} }; //類中的const默認還是可以修改,與C語言const一致 void main() {goodclass good1;goodclass::show(good1);const int *px = &(good1.data); //這里表示指向常量的值std::cout << px << std::endl;int *p = const_cast<int *> (px);//取消常量屬性*p = 123;std::cout << *px << " " << *p << " " << good1.data << std::endl;goodclass::show(good1);std::cin.get(); }
運行結果:
9.在類里面定義一個靜態變量,實現計數并限制QT中彈出窗體,建立QMainWindow的QT項目。(如果想讓QT支持C++11的語法,需要在QT項目的pro文件中加入:CONFIG += c++11,可以再最后面附加上)其中main.cpp的代碼是:
#include "mainwindow.h" #include <QApplication> #include <QDebug> //這個頭文件要加上 class mywindow {public:mainwindow *p; //這里的mainwidow標識的是窗體類static int num; //所有類都可以訪問靜態區mywindow(){if(num > 2)//靜態類成員進行成員{}else{num++;qDebug()<<"create";this->p = new mainwindow;//實例化一個對象this->p->show();//讓這個窗體顯示}}~mywindow(){qDebug() << "delete";delete this->p;} };//對靜態變量賦初值 int mywindow::num = 0;void run() {mywindow my1;//棧上 }int main(int argc, char *argv[]) {QApplication a(argc, argv);mywindow *pwindow = new mywindow;qDebug() << mywindow::num;//通過這行打印出次數//下面是低嗎快{mywindow *pwindow=new mywindow;qDebug() << pwindow->num;}{mywindow *pwindow=new mywindow;qDebug() << pwindow->num;}{mywindow *pwindow=new mywindow;qDebug() << pwindow->num;}return a.exec(); }10.靜態函數和普通函數
#include "mainwindow.h" #include <QApplication> #include <stdlib.h> #include <QDebug>class mywindow { public:MainWindow w;public:static void run() //因為加了static,所以不用實例化就可以用。{system("calc");}void notepad(){system("notepad");} };class mywindowW { public:MainWindow w; //繼承int # public:mywindowW(int data):num(data) //給data初始化{} };int main(int argc, char *argv[]) {QApplication a(argc, argv);mywindow mywindow1;mywindow1.w.show();mywindow1.run(); //第一種調用方式mywindow1.notepad();//mywindow1::notepad();//這種方式不可以直接地調用mywindow::run();//不需要實例化的情況就可以調用return a.exec(); }運行結果是彈出計算器和記事本。
11.函數默認參數,對于給含有默認參數的函數賦值的時候,參數的賦值將從左往右賦值給函數中的參數。
案例如下:
#include "mainwindow.h" #include <QApplication>class mywindow { public:MainWindow w;MainWindow *p;//如果在調用的時候只傳遞一個參數的時候,這個參數賦值給了str1void settitle(char *str1="XYZ",char *str2="THG"){w.setWindowTitle(str1);p->setWindowTitle(str2);} };int main(int argc, char *argv[]) {QApplication a(argc, argv);mywindow my1;my1.p=new MainWindow;my1.w.show();my1.p->show();//傳遞參數的時候,從左往右填充,比如下面的AHNJ將賦值給*str1//可以只傳遞一個參數,也可以傳遞兩個參數my1.settitle("AHNJ");return a.exec(); }
運行結果如下:
12.加了const之后函數和沒有加const變量的函數的區別:
新建QT項目,編寫代碼:
13.關于友元函數,案例如下(不用修改QT的頭文件和頭文件的實現類):
#include "mainwindow.h" #include <QApplication>//友元函數可以訪問類中的私有變量,還可以訪問私有函數 //友元函數聲明的時候要有friend,定義的時候不需要friend了 //定義友元的時候也可以在內的內部 class mywindow {MainWindow *p;void go(){system("notepad");}//聲明一個友元函數void friend showwindow(mywindow * pwin); };//實現一個友元函數 void showwindow(mywindow *pwin) {pwin->p=new MainWindow;pwin->p->show();pwin->go(); }int main(int argc, char *argv[]) {QApplication a(argc, argv);mywindow my1;// my1.p;showwindow(&my1);return a.exec(); }
14.友元類,當指向了一個指針的時候一定要初始化。否則將出現錯誤,下面的函數任然是main.cpp中的內容。
#include "mainwindow.h" #include <QApplication>//被友元 class window {MainWindow *p;void settitle(){this->p->setWindowTitle("1234");}friend class opwindow;//友元類 };class opwindow { private:window pwin; //類的變量,指針可以訪問類的所有私有成員與函數window *ppwin;//指針必須初始化,必須分配內存public:void init(){//不初始化就是野指針,所以這里一定要初始化,不然會報錯ppwin = new window;ppwin->p = new MainWindow();ppwin->p->show();}void setstr(){ppwin->settitle();} };int main(int argc, char *argv[]) {QApplication a(argc, argv);opwindow opwindow1;opwindow1.init();opwindow1.setstr();//語法return a.exec(); }
友元類案例2
頭文件QT項目:
#ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>namespace Ui { class MainWindow; }class MainWindow : public QMainWindow {Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);//重載MainWindow(const MainWindow & w){MainWindow(0);}~MainWindow();private:Ui::MainWindow *ui;//友元類friend class window; };#endif // MAINWINDOW_Hmain.cpp #include "mainwindow.h" #include <QApplication>class window { public:MainWindow w;MainWindow *p; };int main(int argc, char *argv[]) {QApplication a(argc, argv);window window1;window1.w.show();window1.p = new MainWindow(window1.w);window1.p->show();return a.exec(); }
?
?
總結
以上是生活随笔為你收集整理的拷贝构造,深度拷贝,关于delete和default相关的操作,explicit,类赋初值,构造函数和析构函数,成员函数和内联函数,关于内存存储,默认参数,静态函数和普通函数,const函数,友元的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 茅台酒诞生于哪一年?
- 下一篇: 类型转换,类与类之间的转换,继承关系,继