【足迹C++primer】42、拷贝、赋值与销毁(1)

拷贝、赋值与销毁(1)

13.1.1拷贝构造函数

/**************************************
13.1.1拷贝构造函数
**************************************/

class Foo1
{
public:
    Foo1();              //默认构造函数
    Foo1(const Foo1&);    //拷贝构造函数
    //...
};

注意:拷贝构造函数的第一个参数必须是一个参数

合成拷贝构造函数

/**************************************
合成拷贝构造函数
**************************************/
class Sales_data
{
friend Sales_data add(const Sales_data&, const Sales_data&);
friend ostream &print(ostream&, const Sales_data&);
friend istream &read(istream&, Sales_data&);
public:
	// constructors
	Sales_data(): units_sold(0), revenue(0.0) { }
	Sales_data(const string &s):
	           bookNo(s), units_sold(0), revenue(0.0) { }
	Sales_data(const string &s, unsigned n, double p):
	           bookNo(s), units_sold(n), revenue(p*n) { }
	Sales_data(istream &);

	// operations on Sales_data objects
	string isbn() const { return bookNo; }
	Sales_data& combine(const Sales_data&);
	double avg_price() const;

	/*
    与合成的拷贝构造函数等价的拷贝构造函数的声明
    */
    Sales_data(const Sales_data&);
    Sales_data& operator=(const Sales_data&);   //赋值运算符
    ~Sales_data(){}
private:
	string bookNo;
	int units_sold=0;
	double revenue=0.0;
};

//与Sales_data的合成的拷贝构造函数等价
Sales_data::Sales_data(const Sales_data &orig):bookNo(orig.bookNo),
                       units_sold(orig.units_sold),revenue(orig.revenue){}

// nonmember Sales_data interface functions
Sales_data add(const Sales_data&, const Sales_data&);
ostream &print(ostream&, const Sales_data&);
istream &read(istream&, Sales_data&);

// used in future chapters
inline
bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs)
{
	return lhs.isbn() < rhs.isbn();
}

这个类其实在前面第七章就说过了,只是前面那个没有拷贝构造函数,拷贝赋值运算符,析构函数数而已

拷贝初始化

/**************************************
拷贝初始化
**************************************/
void fun1()
{
    string dots(10, '.');   //直接初始化
    string s(dots);         //直接初始化
    string s2=dots;         //拷贝初始化
    string null_book="9-999-99999-9";   //拷贝初始化
    string nines=string(100, '9');      //拷贝初始化
}

拷贝初始化不仅在我们用=定义变量时会发生,在下列情况下也会发生

*将一个对象作为实参传递给一个非引用类型的形参

*从一个返回类型为非引用类型的函数返回一个对象

*用花括号列表初始化一个数组中的元素或一个聚合类中的成员

拷贝初始化的限制

/**
拷贝初始化的限制
*/
void fun2()
{
    vector<int> v1(10);     //正确:直接初始化
//    vector<int> v2=10;      //错误:接受大小参数的构造函数式explicit的
    void f(vector<int>);    //f的参数进行拷贝初始化
//    f(10);                  //错误:不能用一个explicit的构造函数拷贝一个实参
//    f(vector<int>(10));     //正确:从一个int直接构造一个临时的vector
}

13.1.2拷贝赋值运算符

/**************************************
13.1.2拷贝赋值运算符
**************************************/
void fun3()
{
    Sales_data trans, accum;
    trans=accum;        //使用Sales_data的拷贝赋值运算符
}

重载赋值运算符

/**
重载赋值运算符
*/

class Foo2
{
public:
    Foo2& operator=(const Foo2&);     //赋值运算符
    //...
};

合成拷贝赋值运算符

/**
合成拷贝赋值运算符
*/
Sales_data&
Sales_data::operator=(const Sales_data &rhs)
{
    bookNo=rhs.bookNo;      //调用string::operator=
    units_sold=rhs.units_sold;  //使用内置的int赋值
    revenue=rhs.revenue;        //使用内置的double赋值
    return *this;               //返回一个此对象的引用
}

13.1.3析构函数

/**************************************
13.1.3析构函数
**************************************/
class Foo3
{
public:
    ~Foo3();     //析构函数
    //...
};

析构函数自动运行,我们的程序可以按需要分配资源,无需担心何时释放这些资源

void fun4()
{
    //p和p2指向动态分配的对象
    Sales_data *p=new Sales_data;       //p是一个内置指针
    auto p2=shared_ptr<Sales_data>();   //p2是一个shared_ptr
    Sales_data item(*p);        //拷贝构造函数吧*p拷贝到item中
    vector<Sales_data> vec;     //局部对象
    vec.push_back(*p2);         //拷贝p2指向的对象
    delete p;                   //对p指向的对象执行析构函数
}
//退出局部作用域;对item,vec,p2调用析构函数
//销毁p2会递减其引用计数;如果引用计数变为0,对象被释放
//销毁vec会销毁它的元素

FOO类

//Foo类
class Foo4
{
public:
    Foo4(){cout<<"想知道我为何这么屌?"<<endl;}      //默认构造函数
    Foo4(const Foo4&);    //拷贝构造函数
    Foo4& operator=(const Foo4&);     //赋值运算符
    ~Foo4(){cout<<"cutter_point:我就是这么屌!";}                //析构函数
};

Foo4& Foo4::operator=(const Foo4 &f)
{
    cout<<"你为何这么屌cutter_point?";
}

全代码!!!

/**
* 功能:拷贝、赋值与销毁
* 时间:2014年7月11日09:39:06
* 作者:cutter_point
*/

#include<iostream>
#include<string>
#include<vector>
#include<memory>

using namespace std;

/**************************************
13.1.1拷贝构造函数
**************************************/

class Foo1
{
public:
    Foo1();              //默认构造函数
    Foo1(const Foo1&);    //拷贝构造函数
    //...
};

/*
拷贝构造函数的第一个参数必须是一个参数
*/

/**************************************
合成拷贝构造函数
**************************************/
class Sales_data
{
friend Sales_data add(const Sales_data&, const Sales_data&);
friend ostream &print(ostream&, const Sales_data&);
friend istream &read(istream&, Sales_data&);
public:
	// constructors
	Sales_data(): units_sold(0), revenue(0.0) { }
	Sales_data(const string &s):
	           bookNo(s), units_sold(0), revenue(0.0) { }
	Sales_data(const string &s, unsigned n, double p):
	           bookNo(s), units_sold(n), revenue(p*n) { }
	Sales_data(istream &);

	// operations on Sales_data objects
	string isbn() const { return bookNo; }
	Sales_data& combine(const Sales_data&);
	double avg_price() const;

	/*
    与合成的拷贝构造函数等价的拷贝构造函数的声明
    */
    Sales_data(const Sales_data&);
    Sales_data& operator=(const Sales_data&);   //赋值运算符
    ~Sales_data(){}
private:
	string bookNo;
	int units_sold=0;
	double revenue=0.0;
};

//与Sales_data的合成的拷贝构造函数等价
Sales_data::Sales_data(const Sales_data &orig):bookNo(orig.bookNo),
                       units_sold(orig.units_sold),revenue(orig.revenue){}

// nonmember Sales_data interface functions
Sales_data add(const Sales_data&, const Sales_data&);
ostream &print(ostream&, const Sales_data&);
istream &read(istream&, Sales_data&);

// used in future chapters
inline
bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs)
{
	return lhs.isbn() < rhs.isbn();
}

/**************************************
拷贝初始化
**************************************/
void fun1()
{
    string dots(10, '.');   //直接初始化
    string s(dots);         //直接初始化
    string s2=dots;         //拷贝初始化
    string null_book="9-999-99999-9";   //拷贝初始化
    string nines=string(100, '9');      //拷贝初始化
}
/*
拷贝初始化不仅在我们用=定义变量时会发生,在下列情况下也会发生
*将一个对象作为实参传递给一个非引用类型的形参
*从一个返回类型为非引用类型的函数返回一个对象
*用花括号列表初始化一个数组中的元素或一个聚合类中的成员
*/

/**
拷贝初始化的限制
*/
void fun2()
{
    vector<int> v1(10);     //正确:直接初始化
//    vector<int> v2=10;      //错误:接受大小参数的构造函数式explicit的
    void f(vector<int>);    //f的参数进行拷贝初始化
//    f(10);                  //错误:不能用一个explicit的构造函数拷贝一个实参
//    f(vector<int>(10));     //正确:从一个int直接构造一个临时的vector
}

/**************************************
13.1.2拷贝赋值运算符
**************************************/
void fun3()
{
    Sales_data trans, accum;
    trans=accum;        //使用Sales_data的拷贝赋值运算符
}

/**
重载赋值运算符
*/

class Foo2
{
public:
    Foo2& operator=(const Foo2&);     //赋值运算符
    //...
};

/**
合成拷贝赋值运算符
*/
Sales_data&
Sales_data::operator=(const Sales_data &rhs)
{
    bookNo=rhs.bookNo;      //调用string::operator=
    units_sold=rhs.units_sold;  //使用内置的int赋值
    revenue=rhs.revenue;        //使用内置的double赋值
    return *this;               //返回一个此对象的引用
}

/**************************************
13.1.3析构函数
**************************************/
class Foo3
{
public:
    ~Foo3();     //析构函数
    //...
};

/*
析构函数自动运行,我们的程序可以按需要分配资源,无需担心何时释放这些资源
*/
void fun4()
{
    //p和p2指向动态分配的对象
    Sales_data *p=new Sales_data;       //p是一个内置指针
    auto p2=shared_ptr<Sales_data>();   //p2是一个shared_ptr
    Sales_data item(*p);        //拷贝构造函数吧*p拷贝到item中
    vector<Sales_data> vec;     //局部对象
    vec.push_back(*p2);         //拷贝p2指向的对象
    delete p;                   //对p指向的对象执行析构函数
}
//退出局部作用域;对item,vec,p2调用析构函数
//销毁p2会递减其引用计数;如果引用计数变为0,对象被释放
//销毁vec会销毁它的元素

//Foo类
class Foo4
{
public:
    Foo4(){cout<<"想知道我为何这么屌?"<<endl;}      //默认构造函数
    Foo4(const Foo4&);    //拷贝构造函数
    Foo4& operator=(const Foo4&);     //赋值运算符
    ~Foo4(){cout<<"cutter_point:我就是这么屌!";}                //析构函数
};

Foo4& Foo4::operator=(const Foo4 &f)
{
    cout<<"你为何这么屌cutter_point?";
}

int main()
{
    Foo4 *f4=new Foo4();
    delete f4;
    return 0;
}

结果图!!(新产品)

PS:尼玛,完全没法淡定了,大热天的感冒,我的天,我受不了了。。。。。。。。。。。。

【足迹C++primer】42、拷贝、赋值与销毁(1)

时间: 2024-11-05 19:04:28

【足迹C++primer】42、拷贝、赋值与销毁(1)的相关文章

【足迹C++primer】43、拷贝控制和资源管理

拷贝控制和资源管理 13.2.1行为像值的类 *定义一个拷贝构造函数,完成string的拷贝,而不是拷贝指针 *定义一个析构函数来释放string *定义一个拷贝赋值运算符来释放对象当前的string,并从右侧运算对象拷贝string class HasPtr { public: HasPtr(const string &s=string()):ps(new string(s)), i(0){} //对ps指向的string,每个HasPtr对象都有自己的拷贝 HasPtr(const HasP

【足迹C++primer】54、继承类的范围,构造函数和拷贝控制

继承类的范围,构造函数和拷贝控制 当用派生类执行函数的时候,首先会在当前的类里面找 如果找不到就一级一级地往上找. Name Lookup Happens at Compile Time class Quote { public: Quote()=default; Quote(const string &book, double sales_price):bookNo(book), price(sales_price) {cout<<"Quote gouzhao functi

【足迹C++primer】45、拷贝控制示例

拷贝控制示例 那么接下来尽情欣赏这个案例吧!!! /** * 功能:拷贝控制示例 * 时间:2014年7月14日10:57:39 * 作者:cutter_point */ #include<iostream> #include<set> #include<vector> #include<string> using namespace std; class Folder; /** Message类 */ class Message { friend void

拷贝控制——拷贝、赋值与销毁

当定义一个类时,我们显示地或隐式地指定在此类型的对象拷贝.移动.赋值和销毁时做什么.一个类通常定义五种特殊的成员函数来控制这些操作,包括:拷贝构造函数.拷贝赋值运算符.移动构造函数.移动赋值运算符和析构函数.拷贝和移动构造函数定义了当用同类型的另一个对象初始化本对象时做什么.拷贝和移动赋值运算符定义了将一个对象赋予同类型的另一个对象时做什么.析构函数定义了当此类型对象销毁时做什么.我们称这些操作为拷贝控制操作. 如果一个类没有定义这些拷贝控制成员,编译器会自动为它定义缺失的操作.但是,对一些类来

【足迹C++primer】39、动态内存与智能指针(3)

动态内存与智能指针(3) /** * 功能:动态内存与智能指针 * 时间:2014年7月8日15:33:58 * 作者:cutter_point */ #include<iostream> #include<vector> #include<memory> #include<string> using namespace std; /** 智能指针和异常 */ void f() { shared_ptr<int> sp(new int(42));

【足迹C++primer】47、Moving Objects(1)

Moving Objects(1) * 功能:Moving Objects * 时间:2014年7月17日08:46:45 * 作者:cutter_point */ #include<iostream> #include<string> #include<memory> #include<utility> #include<vector> #include<algorithm> #include<set> #include

【足迹C++primer】31、初识泛型算法

初识泛型算法 理解算法的最基本方法是了解他们是否读取元素.改变元素或是重排元素顺序! 只读算法 #include<iostream> #include<numeric> using namespace std; //对vec中的元素求和,初值是0 int sum=accumulate(vec.cbegin(), vec.cend(), 0); 这里面第三个参数决定了函数使用哪个加法运算符以及返回值类型. 算法和元素类型 string sum=accumulate(v.cbegin(

【足迹C++primer】28、额外的string操作

额外的string操作 构造string的其他方法 //n, len2, pos2 都是无符号值 string s(cp, n) //s是cp指向的数组中前n个字符的拷贝.此数组至少应该包含n个字符 string s(s2, pos2) //s是string s2从下标pos2开始的字符的拷贝. string s(s2, pos2, len2) //s是s2从pos2开始Len2个字符 const char *cp="Hello World!!!"; //以空字符结束的数组 char

【足迹C++primer】26、顺序容器操作

顺序容器操作 向顺序容器添加元素 forward_list //有自己专有版本的insert和emplace: forward_list //不支持push_back和emplace_back vector, string //不支持push_front和emplace_front c.push_back(t), c.emplace_back(args) //在c的尾部创建一个值为t的或者由args创建的元素,返回void c.push_front(t), c.emplace_back(args