首页 > 代码库 > 拷贝构造,深度拷贝,关于delete和default相关的操作,explicit,类赋初值,构造函数和析构函数,成员函数和内联函数,关于内存存储,默认参数,静态函数和普通函数,const函数,友元
拷贝构造,深度拷贝,关于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; //将开辟的内存中的内容赋值为0 memset(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: //使用有参构造,使用explicit explicit 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: //使用有参构造,使用explicit classobj(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 = http://www.mamicode.com/90;//const,这种方式初始化就不需要写构造函数了>运行结果:
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; //如果在调用的时候只传递一个参数的时候,这个参数赋值给了str1 void 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项目,编写代码:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT //下面是新添加的 public: int x; int y; mutable int z;//不受const成员函数的约束 public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); void resetxy();//没有const属性,可以修改成员变量 void showxy() const; //const,不可以修改一般的成员变量 private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H 编写MainWindow的实现 #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::resetxy() { this->x = 800; this->y = 600; resize(this->x,this->y); } void MainWindow::showxy() const { //因为是加了const,所以不再可以调用成员变量 //this->x = 10; //因为没有加上mutable,所以不可以调用 //this->y = 100; this->z = 1000; } 调用main函数 #include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; //重置窗口大小 w.resetxy(); w.show(); return a.exec(); }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_OBJECT public: explicit MainWindow(QWidget *parent = 0); //重载 MainWindow(const MainWindow & w) { MainWindow(0); } ~MainWindow(); private: Ui::MainWindow *ui; //友元类 friend class window; }; #endif // MAINWINDOW_H main.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(); }