C++进阶:新人易入的那些坑 --8.杂项

/*
定义:一个函数自己直接调用或间接调用自己
*/
//P8构造和析构函数中的虚函数
/*
Calling Virtual Function in Constructor or Destructor
*/
class Dog
{
public:
	Dog() 
	{
		cout << "dog born." << endl; 
		//bark();
	}
	virtual void bark() { cout << "I am a just a dog" << endl; }
	void seeCat() { bark();}
	~Dog() { bark(); }//bark()调用自身bark()
};

class Yellowdog : public Dog
{
public:
	Yellowdog() { cout << "Yellow dog born." << endl;}
	virtual void bark() { cout << "I am a yellow dog" << endl;}
};

int main()
{
	Yellowdog d;
	d.seeCat();
	return 0;
}

//重载赋值运算符以自我赋值
/*
	Handle self-assignment in operator=
	Operator overload:exploite people's intuition and reduce their learning curve
*/
dog dd;
dd = dd;//Looks silly

dogs[i] = dogs[j];//looks less silly

				  
/* Implementing Assignment Operator*/
class collar;
class dog
{
	collar* pCollar;
	//错误写法
	/*
	dog& operator=(const dog& rhs);
	{
		delete pCollar;
		pCollar = new collar(*rhs.pCollar);
		return *this;
	}
	*/
	//正确写法1
	dog& operator=(const dog& rhs)
	{
		if(this == &rhs)
			return *this;
		collar* pOrigCollar = pCollar;//why
		pCollar = new collar(*rhs.pCollar);
		delete pOrigCollar;
		return *this;
	}
};
//正确写法2:Delegation
class dog
{
	collar *pCollar;
	dog& operator=(const dog& rhs)
	{
		*pCollar = *rhs.pCollar;//member by member copying of collars or call collar's operator=
		return *this;
	}
};
//P10 RAII 资源获取即初始化
/*
Resource Acquisition is Initialization(RAII)
* Use objects to manage resources:
	memory,hardware device,network handle,etc
*/

Mutex_t mu = MUTEX_INITIALIZER;
void functionA()
{
	Mutex_lock(&mu);
	....//Do a bunch of things
    Mutex_unlock(&mu);//will this line always be executed?
}
 
//Solution:
class Lock
{
private:
	Mutex_t* m_pm;
public:
	explicit Lock(Mutex_t *pm)
	{
		Mutex_lock(pm);
		m_pm = pm;
	}
	~Lock() { Mutex_unlock(m_pm); };
};

void functionA()
{
	Lock mylock(&mu);
	...//do a bunch of things
	// The mutex will always be released when mylock
     // is destroyed from stack
}

/*
Conclusion:
	The only code that can be guaranteed to be executed after
	exception is thrown are the destructor of objects residing
	on the stack.
	Resource management therefore needs to be tied to the lifespan
	of suitable objects in order to gain automatic deallocation 
	and reclamation.
*/
/*
Note 1:
	Another good example of RAII: tr1:shared_ptr
*/

int function_A()
{
	std::tr1::shared_ptr<dog> pd(new dog());
	...
}
// The dog is destructed when pd goes out of scope
//(no more pointer points to pd)

//Another example:
class dog;
class Trick;
void train(tr1::shared_ptr<dog> pd,Trick dogtrick);
Trick getTrick();

int main()
{
	//train(tr1::shared_ptr<dog> pd(new dog()), getTrick());//错误写法
	tr1::shared_ptr<dog> pd(new dog());//正确写法
	train(pd, getTrick());
}
//question: what's the problem with above code:
//what happens in train()'s parameter passing:
//1.new dog()
//2.getTrick()
//3.The order of these operations are determined by compiler.

//Conclusion:
//Don't combine storing objects in shared pointers with other statement.

/*
Note 3:
	what happens when resource management object is copied?
*/
Lock L1(&mu);
Lock L2(L1);

/*
Solution 1:
	prohibit copying. To see how to disallow copy constructor and copy
	assignment operator from being used,watch my another session:
	Disallow compiler Generated Functions.
*/

/*
Solution 2:
	Reference-count the underlying resource by using tr1::shared_ptr
*/
template<class Other, class D> shared_ptr(Other *ptr, D deleter);
//The default value for D is "delete",e.g.:
std::tr1::shared_ptr<dog> pd(new dog());
class Lock
{
private:
	std::tr1::shared_ptr<Mutex_t> pMutex;
public:
	explicit Lock(Mutex_t *pm) : pMutex(pm, Mutex_unlock)
	{
		Mutex_lock(pm);
		//The second parameter of shared_ptr constructor is 
		// "deleter" function
	}
};
//P11 静态初始化的失败
/*
Initialization Fiasco
A subtle problem that can crash your program.
*/
//Dog.h
#include <string.h>
class Dog
{
	std::string _name;
public:
	void bark();
	Dog(char* name);
};
//Dog.cpp
Cat c("Smokey");

void Dog::bark()
{
	std::cout << "Dog rules! My name is" << _name << std::endl;
}

Dog::Dog(char *name)
{
	std::cout << "Constructing Dog" << name << std::endl;
	_name = name;
}
//Cat.cpp
#include "cat.h"
#include "Dog.h"
#include <iostream>

extern Dog d;

void Cat::meow()
{
	std::cout << "Cat rules! My name is" << _name << std::endl;
}

Cat::Cat(char* name)
{
	std::cout << "Constructing cat" << name << std::endl;
	_name = name;
	d.bark();
}

//the program should crash,because the cat is contructed before the dog

using namespace std;

Dog d("Gunner");

int main(void)
{
	d.bark();
	return 0;
}

//how to deal with the program
//Singleton.h
class Dog;
class Cat;

class Singleton
{
	static Dog* pd;
	static Cat* pc;
public:
	~Singleton();
	static Dog* getDog();
	static Cat* getCat();
}

//singleton.cpp
#include "singleton.h"
#include "Dog.h"
#include "cat.h"

Dog* Singleton::pd = 0;
Cat* Singleton::pc = 0;

Dog* Singleton::getDog()
{
	if (!pd)
	{
		pd = new Dog("Gummer");
	}
	return pd;
}

Cat* Singleton::getCat()
{
	if (!pc)
	{
		pc = new Cat("Smokey);
	}
	return pc;
}

Singleton::~Singleton()
{
	if (pd) delete pd;
	if (pc) delete pc;
	pd = 0;
	pc = 0;
}
//main.cpp
/*
Initialization Fiasco
A subtle problem that can be crash your program
*/

using namespace std;
int main()
{
	Singleton s;
	Singleton::getCat()->meow();
	return 0;
}

//cat.cpp修改:
//Cat.cpp
#include "cat.h"
#include "Dog.h"
#include <iostream>

extern Dog d;

void Cat::meow()
{
	std::cout << "Cat rules! My name is" << _name << std::endl;
}

Cat::Cat(char* name)
{
	std::cout << "Constructing cat" << name << std::endl;
	_name = name;
	//d.bark();
	Singleton::getDog()->bark();
}

//p12 Advanced C++: struct VS Class
//结构体VS类
//summary
//1.use struct for passive objects with public data,use class for objects with private data;
//2.use setter/getter to access class's data
//3.Avoid making setter/getter if possible
//P13 Advanced c++: Classes with Resource Handles 资源管理类
//Person owns the string through its pointer

class Person
{
public:
	Person(string name) { pName_ = new string(name); }
	~Person() { delete pName_; }
	void printName() { cout << *pName_; }
private:
	string *pName_;
};

int main()
{
	vector<Person> persons;
	persons.push_back(Person("George"));
	//this program should crash,because
	//1."George" is constructed
	//2.A copy of "George" is saved in the vector persons(shallow copy)
	//3."George" is destroyed.
	//and string* pName_ is deleted.
	persons.back().printName();
	cout << "Goodbye" << endl;
}
//what can we do to solve this problem?
//1.Solution 1:
//Define copy constructor and copy assignment operator for deep copying
class Person
{
public:
	Person(string name) { pName_ = new string(name); }
	~Person() { delete pName_; }
	//solution 1:
	Person(const Person& rhs)
	{
		pName_ = new string(*(rhs.pName()));
	}
	string* pName() const
	{
		return pName_;
	}
	Person& operator=(const Person& rhs);//deep copying
	void printName() { cout << *pName_; }
private:
	string *pName_;
};

//2.solution 2:
//Delete copy constructor and copy assignment operator,define clone()
class Person
{
public:
	Person(string name) { pName_ = new string(name); }
	~Person() { delete pName_; }
	void printName() { cout << *pName_; }
	string* pName() const { return pName_; }
	Person* clone()
	{
		return (new Person(*(pName_)));
	}
private:
	Person(const Person& rhs);
	Person& operator=(const Person& rhs);//deep copying
	string *pName_;
};

int main()
{
	vector<Person*> persons;
	persons.push_back(new Person("George"));
	persons.back()->printName();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值