拷贝构造函数,深拷贝,大约delete和default相

系统 1458 0


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

    

执行结果例如以下:

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

    

执行结果是:

赋值案例 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功能,朋友

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

      

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

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

    

 

 

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

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


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论