static
class Account {
public:
static double m_rate;
static void set_rate(const double& x) { m_rate = x; }
private:
}
double Account::m_rate = 8.0;//静态变量必须在类外定义,可以不设初值,但是必须分配内存
int main() {
Account::set_rate(5.0);
Account a;
a.set_rate(7.0);
}
知识小记:
- 静态函数和非静态函数一样只有一份,但是静态函数没有
this
指针,所以只能处理静态变量 - 静态变量必须在类外定义,可以不设初值,但是必须分配内存
- 静态函数可以通过
object
来调用,也可以通过class name
来调用
单例模式(Singleton)
class A {
public:
static A& getInstance(){ return a; }
setup() {...}
private:
A();
A(const A& ths);
static A a;
...
}
不足之处:强制性地生成静态对象。 问题:
- class中有相同class的成员变量的情况下,内存模型是什么样的?
如果是自己类的成员,必须是指针,不过如果有static作修饰的时候可以忽略这个限制。 - getInstance(return a;);是什么意思? 貌似是语法错误。
class A {
public:
static A& getInstance();
setup() {...}
private:
A();
A(const A& rhs);
...
}
A& A::getInstance()
{
static A a;
return a;
}
知识点:
- 构造函数是
private
属性 - 调用
getInstance()
的时候才会创建静态对象,函数结束之后,静态变量仍然存在 getInstance()
返回的是一个静态的引用
cout
class _IO_ostream_withassign : public ostream {
...
};
extern _IO_ostream_withassign cout;
ostream
重载了很多次操作符<<
class template
template<typename T>//注意关键字是typename
class complex
{
public:
complex(T r = 0; T i = 0)
: re (r), im (i)
{}
complex& operator += (const complex&);
T real() const {return re; }
T imag() const {return im; }
private:
T re, im;
friend complex& __doapl(conplex*, const complex&);
}
int main()
{
complex<double> c1(2.5,1.5);
complex<int> c2(2,6);
return 0;
}
注意:typename T
,使用时要明确指出T
是哪个类型
function template
template <class T>//注意关键字是class
inline const T& min(const T& a, const T& b)
{
return b < a ? b : a;//<需要在类中重载
}
注意:class T
,使用时不需要指出T
是哪一个类型
模板还有很多细节,需要继续自己去学习!
namespace
namespace std
{
...
}
三种用法:
- using directive:
using namespace std
- using declaration:
using std::cout
- 调用时才说明:
std::cin
更多细节
- operator type() const;
- explicit complex(…): initialization list{}
- pointer-like object
- function-like object
- namespace
- template spcialization
- standard specialization
- Standard Library
- variadic template(since C++11)
- move ctor(since C++11)
- Rvalue reference(since C++11)
- auto (since C++11)
- lamdba(since C++11)
- range-base for loop(since C++11)
- unordered containers(since C++)
composition(组合)
composition
表示has-a
的关系。
template <class T>
class queue {
protected:
deque<T> c; //底层容器
public:
//以下完全利用deque的操作函数完成
bool empty() const { return c.empty();}
size_type size() const {return c.size();}
reference front() {return c.front();}
reference back() {return c.back();}
//
void push(const value_type& x) {c.push_back(x);}
void pop() {c.pop_front();}
}
queue
中所有的功能都可以通过deque
来实现,这是一种叫作Adapter
的设计模式,相当于对deque
进行改造。这里的deque
表示两端都可以进出的队列。
composition
关系下,容器和组件的生命周期是一起的。
Composition下的构造和析构
构造是由内而外的
Container::Container(...) : Component() { ... };
Container
的构造函数首先会调用Component
的default
构造函数,然后再执行自己的。component
内部也许会有很多个构造函数,编译器不知道要调用哪一个构造函数,所以只能选择默认的,如果需要调用其他的构造函数,则需要自己去手动写。
析构是由外而内的
Container::~Container(...) {... ~Component() };
Container
的析构函数首先执行自己,然后才调用Component
的析构函数。
Delegation(委托)
就是用通过指针或者引用实现的composition
。所以也叫Composition by reference
。cpp
中by reference
包括指针和引用。
//file String.hpp
class StringRep;//前向声明
class String {
public:
String();
String(const char* s);
String(const String& s);
String& operator=(const String& s);
~String();
private:
StringRep* rep;//pimpl
}
委托关系下,容器和组件的生命是不一致的。
这种写法被称之为point to implementation
。也就是说我有一个指针去指向所有实现我的功能的那一个类。这个手法又叫做编译防火墙。
Inheritance(继承)
继承表示is a
的关系。
struct _List_node_base
{
_List_node_base* _M_next;
_List_node_base* _M_prev;
};
template<typename _Tp>
struct _List_node : public _List_node_base
{
_Tp _M_data;
}
父类的数据可以被完整地继承下来。但这并不是继承最有价值的部分,跟虚函数搭配才是最有价值的部分。
从内存的角度来看,子类的对象有父类的成分在里头。结合composition
我们可以得到类似的结论。如下。
- 构造由内而外
首先是Base
的构造函数然后是derived
的构造函数。 - 析构由外而内
首先调用derived
的析构函数然后是base
的析构函数。 注意事项:base class
的dtor
必须是virtual
的,否则就会出现undefined behavior