拷贝构造函数,深拷贝,大约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();
}

上面的执行结果是:

拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,const功能,朋友

void main()
{
string str1(10,"hello");
std::cout << str1.p << std::endl; string str2(str1); //这里说明能够通过
std::cout << str2.p << std::endl; std::cin.get();
}

执行结果例如以下:

拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,const功能,朋友

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();
}

执行结果例如以下:

拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,const功能,朋友

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();
}

执行结果是:

拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,const功能,朋友

赋值案例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();
}

执行结果例如以下:

拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,const功能,朋友

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG90b3R1enVvcXVhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

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();
}

执行结果截图:

拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,const功能,朋友

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG90b3R1enVvcXVhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

分析,上面的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();
}

执行结果是:

拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,const功能,朋友

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG90b3R1enVvcXVhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

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();
}

执行结果:

拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,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();
}


拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,const功能,朋友

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG90b3R1enVvcXVhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

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();
}

执行结果例如以下:

拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,const功能,朋友

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();
}

版权声明:本文博客原创文章。博客,未经同意,不得转载。

上一篇:(转载)内联函数inline和宏定义


下一篇:【Java必修课】通过Value获取Map中的键值Key的四种方法