c++ 要点 学习阶段性总结

刚开始要学习的c++的时候看了一下primer。写了一些代码。有的东西似是而非的。最近一个月又看了一些相关书籍。

1. Inside c++ Object Model

 已经写了一篇笔记。在后面看书的过程中,发现书中该书中讨论的很多东西还是很有用的。站在编译器的角度来理解c++的一些规则。

对于trival ctor等,bitwise copy 都有涉及。这在每本书书讲到深入的时候都是要涉及的。bitwise又与深拷贝,浅拷贝相关(已做笔记)

回头这本书还得翻翻。


2.  template 

先看了primer,感觉没有头绪。看了编程思想的模板相关章节,再回来看primer。好多了。

编程思想有利于理解。但是作为工具书,在完整性方面primer更胜一筹。比如类特化里面再特化方法,不再需要template<> ,在primer有,而编程思想没有。 p568 在类特化外部定义成员数时, 成员之前不能加template<> 标记。


关于偏特化:

template<typename ....> 里面的类型不需要跟非特化版本一样多,只要写出需要的数目。当全部不需要了,写成template<>,也就是完全特化了。

..funtion<typename .., char,,,>()。 而在特化函数体或者类的名字后面跟上类型。类型的数目跟非特化版本一致。前面的类型与本特化的类型列表一致,后面的则跟上char,void等自己需要的版本。


关于traits:

泛型编程很重要的概念就是traits。取得其真正的类型。这是打开stl源码大门的钥匙,在stl 源码剖析里面讲解得挺清楚的。

举个例子: 一个类型有其指针,怎么获得其类型呢?

可以定义一个函数, void func(T * p).  将该指针传入该函数,那么现在T就是指针的真正类型了。traits的原理类似。不过更加高级。。

typedef 得到别名。 在一个比如在一个类A typedef 得到一个value_type。那么想引用A的value_type则使用  A::value_type

		template <class T>
		struct type_addition //非特化版本
		{
			typedef T                value_type;
			typedef T*               pointer;
			typedef T&               reference;
			typedef const T*		 const_pointer;
			typedef const T&  		 const_reference;
		};

		template <>
		struct type_addition<void>
		{
			typedef void             value_type;
			typedef void*            pointer;
			typedef const void*		 const_pointer;
		};

		template <class T>
		struct type_addition<T*> //对于指针类型进行特化。那么如果获得的是一个指针,这里的value_type指向的依旧是其原始类型
		{
			typedef T                value_type;
			typedef T*               pointer;
			typedef T&               reference;
			typedef const T*		 const_pointer;
			typedef const T&		 const_reference;
		};

		template <class T>
		struct type_addition<T&> //对引用特化
		{
			typedef T                value_type;
			typedef T*               pointer;
			typedef T&               reference;
			typedef const T*		 const_pointer;
			typedef const T&		 const_reference;
		};

		template <class T>
		struct type_addition<const T*>
		{
			typedef T                value_type;
			typedef T*               pointer;
			typedef T&               reference;
			typedef const T*         const_pointer;
			typedef const T&		 const_reference;
		};

typedef typename N::length_type 					 length_type;
		typedef typename N::data_type 					 	 data_type;
		typedef typename N::data_pointer 					 data_pointer;
		typedef typename N::const_data_pointer    			 const_data_pointer;

		typedef typename trait::type_addition<N>::value_type node_type;

以上代码源自管景伟教程。源代码写得不错。关键是整个思考过程。可以多加学习。这代码同时也显示了namespace的使用方法。

#include ...

namespace candidate {  // 可以在多个头文件使用相同的namespace。。

  namespace trait {

//实际代码

}

}


3. stl 源码剖析

stl源码剖析里面迭代器分为5类。不同算法,不同的迭代器都会导致代码的不同。 

stl算法使用大量仿函数(函数对象)。使用起来像个函数,其实是对象,针对operator()进行重载。

stl源码剖析对于平衡二叉树讲的挺清楚。红黑树是stl各个容器的基础。红黑树讲得非常不错。懂了。好书。

关于内存管理,提到::operater new, ::operator delete ,placement new 等。allocate,内存管理。 讲到深入处都有关于这方面的话题。so,腾讯的place new问题不是考得太细,而是研究不够深入。primer后面也有相关章节。


4. 复制控制(拷贝构造函数,析构, operator=)

要不要自己定义拷贝构造函数, 问题的重点跟深拷贝浅拷贝是一个话题。看有没有进行空间的配置等(待补充)


5. 引用计数, 智能指针

int *ip = new int(42);
HasPtr ptr(ip, 10);
delete ip;
ptr.set_ptr_val(0); //disaster
这里的问题是ip和ptr中的指针指向同一对象,删除了该对象ptr的指针不再指向有效对象(垂悬指针)。但是,没有办法这个对象是否无效了。所以需要使用引用技术等方法。


6. 句柄 

c++ primer p504

c++中面向对象编程一个颇具讽刺意味的地方是,不能使用对象支持面向对象编程。相反,必须使用指针或引用。 但是指针或引用的使用会加重类用户的负担。

解决方法:c++中一个同用的技术是定义包装类或者句柄类。句柄类存储和管理基类指针。

一下代码源自primer Handle.h。 不仅保存基类指针,而且记录引用次数

#include <stdexcept>
template<class T> class Handle {
public:
	Handle(T *p = 0) : ptr(p), use(new size_t(1)) { }
	T& operator*();
	T* operator->();
	const T& operator*() const;
	const T* operator->() const;
	Handle(const Handle& h) : ptr(h.ptr), use(h.use) {
		++*use;
	}
	Handle& operator=(const Handle&);
	~Handle() {rem_ref();}
private:
	T* ptr; //shared object
	size_t *use;  // count of how many Handles point to *ptr
	void rem_ref() {
		if(--*use == 0) {
			delete ptr;
			delete use;
		}
	}
};

template <class T> 
inline Handle<T>& Handle<T>::operator=(const Handle& rhs) {
	++*rhs.use;
	rem_ref();
	ptr = rhs.ptr;
	use = rhs.use;
	return *this;
}

template<class T> inline T& Handle<T>::operator*() {
	if(ptr) return *ptr;
	throw std::runtime_error("dereference of unbound handle");
}

template<class T> inline T* Handle<T>::operator->() {
	if(ptr) return ptr;
	throw std::runtime_error("access through unbound Handle");
}

template<class T> inline const T& Handle<T>::operator*() const {
	if(ptr) return *ptr;
	throw std::runtime_error("deference of unbound Handle");
}

template<class T> inline const T* Handle<T>::operator->() const {
	if(ptr) return ptr;
	throw std::runtime_error("access through unbound Handle");
}


class Sales_item {
	friend bool operator<(const Sales_item& lhs, const Sales_item& rhs);
	friend class Basket;
public:
	Sales_item() : h() { }
	Sales_item(const Item_base& item) : h(item.clone()) { }
	const Item_base& operator*() const {
		return *h;
	}
	const Item_base* operator->() const {
		return h.operator->();
	}
private:
	Handle<Item_base> h;
};

class Basket {
	std::multiset<Sales_item> items;}

在面试宝典中:句柄是指针的指针。在这里不是很适用。但是应该是一个道理。。


7. const 

1)替换#define

2)在类中的const,可以实现每个对象不同。如

class A {

const size;

A(int t):size(t) { }

这就是必须使用初始化列表而不使用赋值初始化的地方。(初始化列表不用生成临时变量,效率也更高)

3)编译期间常量 static const 在定义的时候就必须赋值。 如static const size  = 10;

4) const 函数可以被const对象和非const对象调用。但是,const 对象不能调用非const常数。(编译器的角度思考。。)

5)考虑

void u(const int * cip) {

int *ip2 = cip;  //不合法的

}

将const的指针赋给非const是不合法的。


8.  异常

待看笔记完善。。。


9. 关于effective c++

里面很多对于实际编程很有意义的条款,可以避开一些错误。有空再看看。据说对笔试面试很有用。


10. 操作符重载 

声明为友元与成员变量的不同之处。

++ 后置的占位符问题

特殊符号。operator-> 返回的是一个指针   a->fun();其实是 (a->fun) ();


杂项:

private定义拷贝构造函数,而不去实现,可以拒绝复制。

public protected private继承的含义。public表示“是一个”。。 private 继承通常 就像继承某些工具集。详见effective c++

有时候很多接口对外隐藏。那么把接口声明为private。这样只有成员函数可以调用(对用户公开的接口)。外部的客户通过对象是不可以直接使用该接口的。private成员变量道理也一样,只有内部成员函数,友元可以直接使用。

两个类相互依存,只要在一个类的前面先声明另一个类就可以了。如primer的Folder 和 Message类。


你可能感兴趣的:(c++ 要点 学习阶段性总结)