C++11笔记

《effective c++》

1.模数数值比较:
普通写法:
	if(3 == A.Length())
	{
		do sth;
	}
	
专业且更好维护写法:
	const int B = 3;
	if(B == A.Length())
	{
		do sth;
	}
改‘3'为别的常量,只用改一个地方
--------------------------------------
2.__cplusplus 宏定义 查看编译器支持的C++版本
std::cout << __cplusplus <<std::endl;

--------------------
3.善用auto语法糖

--------------------
4.ranged-base for:
//容器遍历
for(decl : coll){
	Do Sth.	
}

for(int i : {1,3,5,6,7}){
	std::cout << i << std:: endl;
}

Vector<MyPoint> Ve_Point;
for(auto& i : Ve_Point){
	Do Sth.
}
--------------------
5.虚函数动态绑定应用例子:
绘图父类A,子类B/C/D/E继承,
A* object = new B/C/D/E();
虚函数virtual draw,List<A*> Mylist;
Mylist遍历时调用的是每种图形子类自己的draw;
动态绑定必要条件:虚函数,向上转型,指针调用
--------------------
6.带有虚函数的类,对象内存所占大小会自动加一个指针大小。
编译器会为每个有虚函数的类创建一个虚函数表(vtbl),该虚函数表将被该类的所有对象共享
class A
{
	public:
		virtual vfun1();
	private:
		int idata1,idata2;
}
sizeof(class A) == 2*sizeof(int) + sizeof(指针) //不考虑内存对齐情况下,实际不一定
---------------------
7.重载函数-编译器二义性报错
explicit parameterwidget(QWidget *parent = nullptr,\
                             double* pdAngleDivision = nullptr,\
                             double* pdOverAngle = nullptr,\
                             double* pdOverLength = nullptr,\
                             int* piRepetition = nullptr);
                             
explicit parameterwidget(QWidget *parent = nullptr,\
                             double* pdStartX = nullptr,\
                             double* pdStartY = nullptr);                             

编译器不会根据参数数量匹配,参数类型雷同情况可更改参数顺序;(比如把上例中的INT*挪到第二个)

模板类
calss template

//模板类头文件
//C++模板中 typename关键字 ≈ class关键字;有时必要使用typename
//复数类:接受各类type的输入******************
temppalte<typename T>
calss complex
{
	public:
	complex(T r = 0 ,T  i=0)
		:re (r).im(i)
	{}
	comlpex& operator += (const complex&);
	//内联函数(inline在头文件内定义)-->处理快,但是否真的inline由编译器决定
	T real() const {return re;}
	T imag() const {return im;}
	
	//OOP概念:数据要独立
	private:
	T re , im;
	
	friend complex& __doapl(complex*,const complex);
};

complex<double> c1(2.5,1.5);
complex<int> c2(2,6);


传址为什么比传值好,传地址只要4个字节效率高。


相同class的各个object互为友元。


多层封装(如果多个函数用一个底层功能),提高复用。


操作符重载-非成员函数(全局重载)
complex operator + (const complex& x,const complex&y)
{
	return complex(real(x) + real(y),imag(x)+imag(y));
}
complex c1(2,1);
complex c2;
c2 = c1 + c2;

依靠参数,编译器可区分操作符重载
complex operator + (const complex& x)
{
	return x;
}

complex operator - (const complex& x)
{
	return complex(-real(x),-imag(x));
}
cout << +c1;
一个复数类完整设计思路
头文件
#ifndef __COMPLEX__
#define __COMPLEX__

class complex
{
public:
	// 构造函数
	// 初始化列表在构造函数执行前执行
	// :re(r),im(i) == {this->re = r; this->im = i}
*******************************************************
	complex(double r = 0,i= 0)
	:re(r),im(i) {}
	
	// 复数的实部和虚部
	// 内联函数
*******************************************************
	double real() const() {return re;}
	double imag() const() {return im;}
	
	// 重载 += 操作符
*******************************************************
	complex& operator += (const complex&);
private:
	double re , im;

	friend complex& __doapl(complex*,const complex&);
}
#endif

.cpp:
	//请求编译器内联
	inline complex& __doapl(complex* ths,const complex& r)
	{
		//友元函数允许访问类的私有成员: r.re、r.im
		ths->re += r.re;
		ths->im += r.im;
		return *ths;
	}

	//非成员函数重载,方便其它复用
	//复数 + 复数
	//返回值传值,需要的是重新构造的对象的值。如果不用重新构造,可考虑传址
	inline complex opreator + (const complex& x,const complex& y)
	{
		return complex(x.real() + y.real(),x.imag() + y.imag());
	}
	
	//复数 + 实数...
	//实数 + 复数...

	//请求编译器内联-成员函数
	inline complex::operator += (const complex& r)
	{
		return __doapl(this,r);
	}

BigThree

C++编译器会自动创建
析构函数(Destructor)~
复制构造函数(copy constructor) People P2(P1)
复制赋值运算符(copy assignment operator)People P2 = People P1

三法则(英语:The Big Three;三法则,三大定律)在 C++ 程序设计里,它是一个以设计的基本原则而制定的定律。
三法则的要求在于,假如类有明显地定义下列其中一个成员函数,那么程序员必须连其他二个成员函数也一同编写至类内,亦即下列三个成员函数缺一不可。
析构函数(Destructor)
复制构造函数(copy constructor)
复制赋值运算符(copy assignment operator)
上述三个函数是特别的成员函数,假如程序员没有自行定义或是编写声明它们,那么编译器会自动地创建它们,并且会编译至应用程序内。

编译器实现new操作过程

Complex* A = new Complex(2,1);
Operator new == malloc(n);

1. void *mem = operator new (sizeof(Complex));//申请地址
2. A = static_cast<Complex*>(mem);//类型转换
3. A->Complex::Complex(2,1);//构造函数

编译器实现delete操作过程

delete A;
Operator delete() == free()

A->Complex::~Complex();//析构函数
Operator delete(A);//

数组\字符串 要用delete[] 保证删除所有分配的内存内容

组合(Compositions)

Container容器类使用到了component组件类
构造函数顺序:首先调用component的默认(defalut)构造函数,再自己的构造函数.由内而外
析构函数顺序:先调用自己的(Container)析构函数,再调用component的析构函数.由外而内

委托(Delegation)

本质为Compositions by reference

"Handle\body"设计模式,编译防火墙(客户端不用重复编译,实现端更改)(待补全)
"Copy On write"概念,变动时复制一份变动(待补全)

继承(Inheritance)

父类的析构函数要设为Virtual
non-virtual函数:不希望被子类重新定义.
virtual函数:已有默认定义,也可以被子类重构.
pure virtual函数:父类本身无定义,一定要子类重写.

设计模式:Template Method

在这里插入图片描述

抽象类(AbstractClass): 定义一组基本方法供子类实现,定义并实现组合了基本方法的模板方法。
具体子类 (ConcreteClass):  实现原语操作以完成算法中与特定子类相关的步骤。

类的转换函数(conversion function)

//分数类,只要类的转换合理,可以写多个转换函数。operator type() const{xxx}
class Fraction
{
	public:
		Fraction(int num,int den = 1)
			:m_numerator(num),m_denominator(den)
			
		operator double() const{
			return (double)  (m_numerator/m_denominator);}
			
	private:
		int m_numerator;
		int m_denominator;
}

Fraction f(3,5);
double a = 4 + f;

执行到 “double a = 4 + f;”时,编译器想要编译通过,
编译器会去找是否有“+”的重载;
没有,则找转换函数,编译器发现可以编译通过。

隐式转换(non-explicit-one-argument ctor)

explicit关键字只对有一个参数的类构造函数有效, 如果类构造函数参数大于或等于两个时, 是不会产生隐式转换的。
但是, 也有一个例外, 就是当除了第一个参数以外的其他参数都有默认值的时候, explicit关键字依然有效, 此时, 当调用构造函数时只传入一个参数, 等效于只有一个参数的类构造函数。
 
class Fraction
{
	public:
		Fraction(int num,int den = 1)
			:m_numerator(num),m_denominator(den)
		Ⅰ:
		operator double() const{
			return (double)  (m_numerator/m_denominator);}
		Ⅱ://+后只允许Fraction同类相加
		Fraction operator + (const Fraction& f){
			return ...;
	private:
		int m_numerator;
		int m_denominator;
}

Fraction f(3,5);
double a = f + 4;
1.当只存在Ⅱ时:编译器找到了+的重载,同时Fraction的构造除了第一个参数外都有默认值,允许隐式转换。会自动把4转换成 Fraction(4,1)。

2.当Ⅰ和Ⅱ同时存在:编译器会Error,ambiguous歧义。

3.当构造函数前加上“explicit”关键字,不允许隐式转换,f可以转换成double,但是“4”
转换不成Fraction,Error。

类的模仿分类:1.像指针;2.像函数
Pointer-like classes

1:智能指针:模板类+重构“*”,“()”操作符。
在这里插入图片描述2:迭代器:模板类+重构“*”,“()”,“++”,“–”
在这里插入图片描述


function-like classes

仿函数类(重载"()")
在这里插入图片描述


namespace

命名空间,防止重名误解,所有自己定义的类都可以考虑加。


Funtion template 模板函数

模板会编译两次,第一次检查语法,第二次检查功能是否有实现。
编译器会自动根据实参类型推导。
template<class T> ≈ template<typename T>;

在这里插入图片描述


Member template 成员模板

在这里插入图片描述


模板特化\局部特化

当全特化和函数重载同时存在时,重载优先!

数量不定的模板参数(Variadic Templates)

Parameter pack(SINCE C++11)
A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates).
A function parameter pack is a function parameter that accepts zero or more function arguments.
A template with at least one parameter pack is called a variadic template. 

参数包:
模板参数包是一个模板参数,它能包含0个或者多个(无类型模板参数类型模板参数\模板)模板参数。
函数参数包同上,只是能接收0个或者多个函数参数。
至少有一个参数包的模板称为数量不定的模板参数。
相关操作符:sizeof...()

typename 
void print(){
}

template<typename T,typename... Types>
void print(const &T first,const &Type... args)
{
	
}

虚函数动态绑定,向上转型

因为,虚函数是以动态绑定的,因此,在向上转型后也是匹配的派生类的版本。
而派生类的其他方法和属性都被隐藏了,可以通过专门的虚函数来间接访问或者调用。
 
 #include <iostream>

using namespace std;

class A {

public:
    A() : m(20) {}
    void show() { cout << "A show: " << m << endl; }
    virtual void display() { cout << "A display: " << m << endl; }

private:
    int m;

};

class B : public A
{

public:
    B() : m(40) {}
    void show() { cout << "B show: " << m << endl; }
    virtual void display() { cout << "B display: " << m << endl; }

private:
    int m;

};

int main()
{
    // 定义上执行对象
    A* a = new B;
    // 调用静态绑定的方法show
    a->show();
    // 调用动态绑定的方法display
    a->display();
    return 0;
}
————————————————结果:
A show: 20
B display: 40
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值