上一篇面向对象高级编程(上)链接
可以把一个类自动转换为别的类型,如fraction转换为double
class Fraction{
public:
...
operator double() const{ //常量函数,该常量就常量. 转换成任何类型都可以
return (double)(分子/分母);
}
}
//使用
Fraction my_frac(3,5);
double d = 4 + my_frac;//调用operator double,my_frac转为0.6
3就是3/1,
class Fraction{
public:
Fraction(int num,int den=1):分子(num),分母(den){}
Fraction operator+(const Fraction& f){
return Fraction(...);
}
};
Fraction my_frac(3,5);
double d = 4 + my_frac;//调用non-explicit ctor将4转为fraction 4/1,然后调用operator+
class Fraction{
public:
explict Fraction(int num,int den=1):分子(num),分母(den){}//不加会出现歧义
operator double() const{
return (double)(分子/分母);
Fraction operator+(const Fraction& f){
return Fraction(...);
}
}
Fraction my_frac(3,5);
double d = 4 + my_frac;//4不能转换为fraction了,加法不能进行
像指针的类,用起来跟指针一样,但是有更多的机制。
链表的node也是一种pointer-like classes。
T& reference operator*()const{
return (*node).data; //用*调用的时候,返回的时候node的data部分,即某个列表元素
}
T* pointer operator->() const{
return &(operator*()); //这里返回某个列表元素的地址
}
list<Foo>::iterator ite;
*ite; //获得一个Foo object
ite->method(); //调用Foo::method;
让一个类像函数被调用,只要实现()操作符即可。
把区域分隔开。用::访问特定区域。
设计一个函数,调用的时候编译器进行实参推导,推导出T为stone
把模板泛化的部分锁定
//泛化
template<class Key>
struct hash{};
//特化
template<>
struct hash<int>{
size_t operator()(int x) cosnt{return x;}
};
cout<<hash<int>()(1000);//hash()表示是临时对象,(1000)启动operator()重载
//泛化模板
template<typenamte T, typename Alloc=...>//模板参数
class vector{
...
};
//个数上的偏特化
template<typename Alloc=...>
class vector<bool, Alloc>{
...
};
任意类型缩小为指针
//泛化模板
template<typename T>
class C{
...
};
//针对指针的偏特化模板
template<typename T>
class C<T*>{
...
};
c<string> obj1; //使用泛化模板
c<string*> obj2; //使用偏特化模板
一个模板参数本身也是一个模板,这里比较高深了,看看就行了
template <typename T,
template<typename T> class Container
>
class XCls{
private:
Container<T> c;
...
};
//使用
template<typename T>
using Lst = list<T,allocator<T>>;
XCls<string, Lst>mylst2;
void print(){
}
template<typename T,typename... Types>//typename...任意个数的模板
void print(const T& firstArg,const Types&... args){//一个和一包
cout<<firstArg<<endl;
cout<<sizeof...(args)<<endl; //这里就知道参数包的size大小
print(args...); //递归调用
}
//使用
print(7.5,"hello",bitset<16>(377),42);
以前:
list<string> c;
list<string>::iterator it;
it = find(c.begin(),c.end(),target);
使用auto:
//auto写
list<string> c;
auto it = find(c.begin(),c.enmd(),target);//让编译器推it的类型
//如错误写法
auto it;
it = find(c.begin(),c.enmd(),target);
一种新的for循环方式
//临时遍历
for (int i: {2,3,4,7} ){//{2,3,4,7}也是c++11里面形成容器的方式
cout<<i<<endl;
}
vector<double> vec;
...
for(const auto elem:vec){ //pass-by-value
cout<<elem<<endl;
}
for(const auto& elem:vec){ //pass-by-reference
elem*=3;
}
引用就是代表,是同一块地址的别名
int x = 0;
int* p = &x; //取指针
int& r = x; //取引用,r代表x,r,x现在都是0,且地址相同
int x2 = 5;
r = x2; //覆盖赋值,即x被赋值为5
int& r2 = r; //传递性,r2同样引用x,r、x、r2都是5
传参时 指针、值、引用的比较:
void f1(Cls* pobj){pobj->xxx();}
void f2(Cls obj){obj.xxx();}
void f3(Cls& objs){obj.xxx();} //注意是不同函数,如果是同一个函数就会报错,编译器二义性错误
Cls obj;
f1(&obj);
f2(obj);//f2和f3的调用参数一致,不像指针,入参需要设置为&obj
f3(obj);
只要类中有虚函数,就有vptr,它指向vtbl,表里面放的都是函数指针,指向内存里面的虚函数。
c++编译器进行函数调用的时候,有两种形式:
动态绑定也就是实现多态的底层原理
通过一个对象调用函数,对象的地址就是this
const在修饰成员函数时要放在()和 {}之间,表示不改变成员函数,全局函数不能这么用
当成员函数的const和non-const版本同时存在,
const object 只能调用const版本。
non-const object只能调用non-const版本。
const object不能调用non-const member function,const member function不能调用non-const member function