C++面向对象高级编程(下)
(学C++就是为了效率,要注意小的习惯,一出手就不同凡响!)
1、Header(头文件)中的防卫式声明
complex.h
#ifndef _COMPLEX_
#define _COMPLEX_
...
#endif
2、如果 成员函数 只读 数据(成员变量),而不去修改,则该 成员函数 后面要加 const
。
const object(data members 不得修改) |
non-const object(data members 可修改) |
|
---|---|---|
const member functions (保证不更改data members) |
√ | √ |
non-const member functions (不保证data members不变) |
× | √ |
const String str("hello C++");
str.print();
//如果当初设计String::print() 时未指明 const
//那么上行便是经由const object 调用 non-const object member function,会出错。
除了上述规则,当成员函数的const
和 non-const
版本同时存在时:
const object
只会(只能)调用 const
版本,non-const object
只会(只能)调用 non-const
版本。calss template std::basic_string<…>有如下两个 member functions:
charT
operator[](size_type pos)const
{.../*不必考虑Copy On Write, 常量对象一定不会改内容!*/ }
reference
operator[](size_type pos)
{.../*必须考虑Copy On Write*/ }
const
算函数签名的一部分!
3、参数传递 尽量 都传引用 &
(速度更快),但是传过去又不想被改,就加 const
;返回类型也 尽量 返回引用 &
4、相同class 的各个objects 互为 friends (友元)
class complex{
public :
complex (double r = 0 , double i = 0): re (r), im (i)
{ }
//complex() : re(0), im(0) {} //错误,和第一个冲突了
double real ()const { return re; }//不希望改变,函数就加const
double imag ()const { return im; }
int func (const complex& param)//互为 friends
{return param.re + param.im;}
private:
double re, im;
} ;
{
complex c1(2, 1);
complex c2;
c2.func(c1) ;
}
5、以下不能返回引用,函数体内创建的对象,离开函数就死亡了!
inline complex operator+ (const complex& x, const complex& y)
{
return complex(real(x) + real(y), imag(x) + imag(y));//类型名 + 小括号 (创建临时对象)
}
inline complex operator+ (const complex& x, double y)
{
return complex(real(x) + y, imag(x));
}
inline complex operator + (double x, const complex& y)
{
return complex(x + real(y), imag(y));
}
6、如果拷贝带指针,一定不要用编译器默认版本,要自己写!(防止浅拷贝)
class String
{
public:
String(const char* cstr = 0);
String(const String& str);
String& operator=(const String& str);
~String();
char* get_c_str() const { return m_data; }
private:
char* m_data;//指针
};
inline String::String(const char* cstr = 0)
{
if (cstr) {
m_data = new char[strlen(cstr)+1];
strcpy(m_data, cstr);
} else {// 未指定初值
m_data = new char[1];
*m_data = '\0';
}
}
//析构
inline String::~String()
{
delete[] m_data;//一定要杀掉删除
}
//拷贝构造
inline String::String(const String& str)
{
m_data = new char[ strlen(str.m_data) + 1 ];//深拷贝
strcpy(m_data, str.m_data);
}
//拷贝赋值
inline String& String::operator=(const String& str)
{
if (this == &str)//一定要检测自我赋值,可能指向同一个空间
return *this;
delete[] m_data;//搭配 array new
m_data = new char[ strlen(str.m_data) + 1 ];
strcpy(m_data, str.m_data);
return *this;
}
7、(stack)栈、(heap)堆与内存管理
Stack
, 是存在于某作用域(scope)的一块内存空间(memory space)。(离开作用域,系统会自动清理!)
Heap
, 或谓 system heap, 是指由操作系统提供的一块 global内存空间,程序可动态分配(dynamic allocated),使用new
创建,从某中获得若干区块(blocks)。(此开辟的空间使用完,需要我们手动释放 delete
,不然会内存泄漏!)
8、new
: 先分配 memory , 再调用构造函数
Complex* pc = new Complex(1,2);
编译器转化为:
Complex *pc;
void* mem = operator new( sizeof(Complex) ); //第一步、分配內存(new 其内部调用malloc(n))
pc = static_cast(mem); //第二步、转型
pc->Complex::Complex(1,2); //第三步、构造函数
8、delete
: 先调用析构函数,再释放 memory
Complex* pc = new Complex(1,2);
...
delete pc;
编译器转化为:
Complex::~Complex(pc); // 第一步、析构函數
operator delete(pc); //第二步、释放內存 (delete 其内部调用 free(pc))
9、静态变量 要用 静态函数 调用。
class Account {
public:
static double m_rate; //只是声明,静态变量
static void set_rate(const double& x) { m_rate = x; }//静态函数
};
double Account::m_rate = 8.0; //赋初值
int main() {//调用static函数的方式有两种:
Account::set_rate(5.0);//1、通过class name调用
Account a;
a.set_rate(7.0);//2、通过object调用
}
推荐写法:
class A {
public:
static A& getInstance();
setup() { ... }
private:
A();
A(const A& rhs);
...
};
A& A::getInstance()//只有别人调用这个函数时,才会生成静态变量a,且只有一份
{
static A a;
return a;
}
10、class template, 类模板
template<typename T>
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 (complex*, const complex&);
};
//使用
{
complex<double> c1(2.5, 1.5);
complex<int> c2(2, 6);
...
}
11、namespace
namespace std
{
...
}
#include
using namespace std;
int main()
{
cin << ...;
cout << ...;
return 0;
}
12、Object Oriented Programming, Object Oriented Design (OOP, OOD)
面向对象类和类的关系:
1)、Composition (复合),表示: has-a
下面的设计模式为:Adapter
template <class T, class Sequence = deque<T>>
class queue {//队列
...
protected :
Sequence c; //底层容器
public:
// 以下完全利用 c 的操作函数完成
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(); }
}
等价于:
template <class T>
class queue {
...
protected:
deque<T> c; // 底層容器
public:
…
}
2)、Delegation (委托)。 Composition by reference.(编译防火墙)
左边(Handle)(拥有指针)指向右边(Body),不是同时存在的,只有左边用到右边时,右边才存在。
左边(Handle)
// 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,指向右边的指针
};
右边(Body)
// file String.cpp
#include "String.hpp"
namespace {
class StringRep {
friend class String;
StringRep(const char* s);
~StringRep();
int count;
char* rep;
};
}
String::String(){ ... }
...
3)、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;
};
base class 的 dtor,必须是 virtual
,否则会出现undefined behavior
13、Inheritance (继承) with virtual functions(虚函数)(成员变量继承占用内存,函数继承的是 调用权 )
class Shape {
public:
virtual void draw( ) const = 0;//pure virtual
virtual void error(const std::string& msg);//impure virtual
int objectID( ) const;//non-virtual
...
};
class Rectangle: public Shape { ... };
class Ellipse: public Shape { ... };
14、Inheritance(继承)+Composition(复合)关系下的构造和析构
14、Delegation(委托) + Inheritance(继承)关系下的构造和析构
Subject
class Subject
{
int m_value;
vector<Observer*> m_views;
public:
void attach(Observer* obs)
{
m_views.push_back(obs);
}
void set_val(int value)
{
m_value = value;
notify();
}
void notify()
{
for (int i = 0; i < m_views.size(); ++i)
m_views[i]->update(this, m_value);
}
};
Observer(将来可能被继承)
class Observer
{
public:
virtual void update(Subject* sub, int value) = 0;
};
Image
#include
enum imageType
{
LSAT, SPOT
};
class Image
{
public:
virtual void draw() = 0;
static Image *findAndClone(imageType);
protected:
virtual imageType returnType() = 0;
virtual Image *clone() = 0;
// As each subclass of Image is declared, it registers its prototype
static void addPrototype(Image *image)
{
_prototypes[_nextSlot++] = image;
}
private:
// addPrototype() saves each registered prototype here
static Image *_prototypes[10];
static int _nextSlot;
};
Image *Image::_prototypes[];
int Image::_nextSlot;
// Client calls this public static member function when it needs an instance
// of an Image subclass
Image *Image::findAndClone(imageType type)
{
for (int i = 0; i < _nextSlot; i++)
if (_prototypes[i]->returnType() == type)
return _prototypes[i]->clone();
}
LandSatImage
class LandSatImage: public Image
{
public:
imageType returnType() {
return LSAT;
}
void draw() {
cout << "LandSatImage::draw " << _id << endl;
}
// When clone() is called, call the one-argument ctor with a dummy arg
Image *clone() {
return new LandSatImage(1);
}
protected:
// This is only called from clone()
LandSatImage(int dummy) {
_id = _count++;
}
private:
// Mechanism for initializing an Image subclass - this causes the
// default ctor to be called, which registers the subclass's prototype
static LandSatImage _landSatImage;
// This is only called when the private static data member is inited
LandSatImage() {
addPrototype(this);
}
// Nominal "state" per instance mechanism
int _id;
static int _count;
};
// Register the subclass's prototype
LandSatImage LandSatImage::_landSatImage;
// Initialize the "state" per instance mechanism
int LandSatImage::_count = 1;
SpotImage
class SpotImage: public Image
{
public:
imageType returnType() {
return SPOT;
}
void draw() {
cout << "SpotImage::draw " << _id << endl;
}
mage *clone() {
return new SpotImage(1);
}
protected:
SpotImage(int dummy) {
_id = _count++;
}
private:
SpotImage() {
addPrototype(this);
}
static SpotImage _spotImage;
int _id;
static int _count;
};
SpotImage SpotImage::_spotImage;
int SpotImage::_count = 1;
// Simulated stream of creation requests
const int NUM_IMAGES = 8;
imageType input[NUM_IMAGES] =
{
LSAT, LSAT, LSAT, SPOT, LSAT, SPOT, SPOT, LSAT
};
main
int main()
{
Image *images[NUM_IMAGES];
// Given an image type, find the right prototype, and return a clone
for (int i = 0; i < NUM_IMAGES; i++)
images[i] = Image::findAndClone(input[i]);
// Demonstrate that correct image objects have been cloned
for (i = 0; i < NUM_IMAGES; i++)
images[i]->draw();
// Free the dynamic memory
for (i = 0; i < NUM_IMAGES; i++)
delete images[i];
}