十三章 札记--C++ primer 之旅


  
复制构造函数:
      定义: 一种特殊构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用
     调用: 当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数
当将该类型的对象传递给函数或从函数返回该类型的对象是,将隐式使用复制构造函数

析构函数:
     定义: 析构函数可用于释放对象在构造或在对象的生命期中所获得的资源。
     调用:当对象超出作用域或动态分配的对象被删除时,自动应用析构函数。

赋值操作符:可以通过制定不同类型的右操作数而重载。

复制构造函数、赋值操作符和析构函数 总称为复制控制


复制构造函数:
     两种初始化形式: 直接初始化; 复制初始化
     当用于类类型对象时:
                                    直接初始化:直接调用与实参匹配的构造函数。
                                    复制初始化:调用复制构造函数。 首先使用指定构造函数创建一个临时对象,然后用复制构造函数将临时对象复制到正在创建的对象。(两个步骤)

   复制初始化条件: 支持复制的类型 且 构造函数非explicit

初始化容器元素: EX: 可以用表示容量的单个形参来初始化容器,这种容器的构造方式使用了默认的构造函数 和 复制构造函数。
          vector<string> svec(5); // 首先 使用string 默认构造函数创建一个临时值 来初始化svec,然后使用复制构造函数将临时值复制到每个svec的每个元素。


构造函数与数组元素:
     如果没有为类类型数组提供元素初始式,将用默认构造函数初始化每个对象。 如果使用常规的花括号括住 的数组初始化类表。  则使用复制构造函数来初始化。根据指定值创建适当类型的元素,然后用复制构造函数将该值复制到相应元素(两步:构造-> 复制)

     
合成的复制构造函数: 执行逐个成员初始化,将新对象初始化为原对象的副本。 直接复制内置类型成员的值,类类型成员使用该类的复制构造函数进行复制。


禁止复制:
     为了防止复制,类必须显式声明其复制构造函数为private。如果连友元和成员中的复制也禁止,可以声明一个 private 复制构造函数但不对其定义。

注意:如果定义了复制构造函数,也必须定义默认构造函数。( 前面讲到的初始化容器列表或数组 可知 )



智能指针:
     智能指针类将一个计数器与类指向的对象相关联。使用计数跟踪该类有多少个对象共享同一指针。

使用计数类: 定义一个单独的具体类用以封装使用计数和相关指针

智能指针: 这些类在对象间 共享 同一基础值,从而提供了指针型行为。


以书上的两个习题作为笔记吧:

今天coding的时候发生了触发了这个assert 
     Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
经过百度,原因:释放了某些内存空间,但是程序里面还保留着对这个内存空间的应用或指针。

复制控制  的程序示例

书上那个信息处理示例:
已注释
Message 类的头文件
#ifndef MESSAGE_H
#define MESSAGE_H


#include <string>
#include <set>

class Folder;		// 同 Folder.h 的声明一样

class Message
{
public :
	Message(const std::string &str=""):contents(str){}// 构造函数
	Message(const Message&);			  //复制构造函数
	Message& operator = (const Message&);		 // 重载赋值运算符

	~Message();
	void save(Folder &);
	void remove(Folder &);

private:
	std::string contents;
	std::set<Folder*>folders;

	void put_Msg_in_Folders(const std::set<Folder*>&);

	void remove_Msg_form_Folders();

	//  [7/19/2012 LSFF]
	void addFldr(Folder *);
	void remFldr(Folder *);
};

#endif
Message 类的实现文件:
#include "Message.h"
#include "Folder.h"
#include <iostream>
#include <set>


Message::Message(const Message & m):				
	contents(m.contents), folders(m.folders)
{
	put_Msg_in_Folders(folders);					
}

	void Message::put_Msg_in_Folders(const std::set<Folder *>& rhs)	// 在folders 里面的每个Fold添加指向 msg的指针 
{
	for(std::set<Folder*>::const_iterator beg = rhs.begin();
						beg!=rhs.end(); ++beg)
		(*beg)->addMsg(this);
	
}


Message& Message::operator = (const Message &rhs)
{
	if(&rhs!=this)							// 赋值运算 会修改左操作数的值,所以应该判断右操作数跟左操作数是同一个
	{
		remove_Msg_form_Folders();
		contents = rhs.contents;
		folders = rhs.folders;
		put_Msg_in_Folders(rhs.folders);
	}
	return *this;
}

void Message::remove_Msg_form_Folders()
{
	for(std::set<Folder*>::const_iterator beg = folders.begin();
									beg!=folders.end(); ++beg)
		(*beg)->remMsg(this);
}

Message::~Message()
{
	remove_Msg_form_Folders();
}

void Message::addFldr(Folder * nf)
{
	folders.insert(nf);
}

void Message::remFldr(Folder *of)
{
	if(folders.count(of)){
		folders.erase(of);
		of->remMsg(this);
	}

}

void Message::save(Folder& nf)
{
	addFldr(&nf);
	nf.addMsg(this);
}

void Message::remove(Folder& of)
{
	remFldr(&of);
	of.remMsg(this);
}
Folder 类的头文件:
#ifndef  FOLDER_H
#define  FOLDER_H

#include <set>	  //下面有用到set容器,所以include 头文件
class Message;	  // 只是在文件中声明Message 类,不需 包括Message 头文件,声明class Message 即可

class Folder
{
public:
	void addMsg( Message* );
	void remMsg( Message* );

private:
	std::set<Message*> msgs;
};

#endif
Folder类 的实现文件
#include "Folder.h"					// 包含编译cpp 文件需要用到的头文件 
#include "Message.h"				// 有用到Message 类的函数调用,所以要包含该头文件



void Folder::addMsg(Message*  nm)
{
	msgs.insert(nm);
}

void Folder::remMsg(Message*  om)
{
	if(msgs.count(om))
		msgs.erase(om);
}
main 文件
#include<iostream>
#include"Message.h"
#include"Folder.h"
using std::cout;
using std::cin;
using std::endl;


int main()					// 下面的用例是随便弄的,调试的时候监视变化即可。
{
	Folder fldr1;
	Folder fldr2;
	Message newMsg1("helloword");
	Message newMsg2("byeword");
	

	newMsg1.save(fldr1);d
	newMsg1.save(fldr2);

	newMsg2=newMsg1;

	return 0;
}

智能指针的code 实例:
 (已注释)
智能指针类 U_Ptr 的头文件
#ifndef  U_PTR_H		// 智能指针类的头文件
#define  U_PTR_H
class HasPtr;
#include <iostream>
using std::cout;
using std::endl;

class U_Ptr
{
	friend class HasPtr;		// 把定义智能指针的类,即该类里面有指向智能指针类的指针成员。把该类设为友元。即能在该类里面直接访问智能指针
	int *ip;			// 真正指向 对象间共享的数据的 指针
	size_t use;			// 目前指向本对象的指针数。 
					// 某个智能指针类的对象在 "包含它的类" 定义某个对象时 也就定义了, 
					//而"包含它的类" 只是存储此对象的指针。 在这个“包含它的类" 的对象
					//发生复制、赋值时 就通过其存储的指针改变 这些智能对象的指针数
													
	U_Ptr(int *p): ip(p), use(1){}	// 定义的时候只有一个指针指向它
	~U_Ptr(){ cout<<"delete:"<<*ip<<endl;delete ip; }
};

#endif
包含U_Ptr 类的 HasPtr 类 头文件
#ifndef  HASPTR_H
#define HASPTR_H
#include "U_Ptr.h"			// 在这里不能只声明 class U_Ptr ,因为下面有函数用到U_Ptr 类里面的成员。其实可以通过只声明这些函数而在对应cpp文件中再实现
class U_Ptr;				// 那样就可以include "U_Ptr.h" 头文件,但是inline函数一定要在头文件中实现。 所以二者应该不能兼得。
					// 通过只声明 class U_Ptr ,只能定义 该类指针、引用,或作为函数参数,不能定义该类。
class HasPtr
{
public :
	HasPtr(int *ip, int i): ptr(new U_Ptr(ip)), val(i){};	// new 函数返回的是 申请内存的地址,谨记谨记。赋给指针

	HasPtr (const HasPtr& hp):ptr(hp.ptr), val(hp.val){ ++ptr->use; }

	HasPtr & operator = (const HasPtr&) ;

	~HasPtr ()
	{
		if(--ptr->use == 0) delete ptr;
	}
private:
	int val;
	U_Ptr *ptr;
};

#endif
 HasPtr 类 实现文件
#include<iostream>
#include "HasPtr.h"
#include "U_Ptr.h"//

HasPtr & HasPtr::operator=(const HasPtr & rval)
{
	++rval.ptr->use;				// 先加 右操作数 的use 数,再减去 左操作数的 use数,是为了防止 左右操作数是同一个的情况。
	if(--ptr->use==0)
		delete ptr;

	ptr=rval.ptr;
	val=rval.val;

	return *this;
}
main 文件:
#include <iostream>
#include "HasPtr.h"

int main()
{

	HasPtr hp1(new int(4),3);
	HasPtr hp2(hp1);

	HasPtr hp3(new int(5),4);

	hp1=hp3;
	hp2=hp3;

	return 0;

}



















  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值