C++05模板
作者:互联网
C++模板
友元函数
关键字:friend
友元全局函数:将全局函数声明为友元函数就是友元全局函数,可以访问到私有数据成员和私有成员函数。friend void printTime(Time &t);
#include<iostream>` `using namespace std;` `class Time{` `friend void printTime(Time &t);` `public:` `Time(int hour,int minute,int second);` `private:` `int m_iHour;` `int m_iMinute;` `int m_iSecond;`
};
==========================================
#include "Time.h"
Time::Time(int hour,int minute,int second){
m_iHour=hour;
m_iMinute=minute;
m_iSecond=second;
}
=========================================
#include<iostream>
#include"Time.h"
using namespace std;
void printTime(Time &t){
cout<<t.m_iHour<<":"<< t.m_iMinute<<":"<<t.m_iSecond<<endl;
}
int main(int argc, char *argv[]) {
Time t(6,34,12);
printTime(t);
}
友元成员函数:将成员函数声明为友元函数就是友元成员函数friend void Match::printTime(Time &t);
#ifndef T_Time
#define T_Time
#include<iostream>
#include"Match.h"
using namespace std;
class Time{
friend void Match::printTime(Time &t);
public:
Time(int hour,int minute,int second);
private:
int m_iHour;
int m_iMinute;
int m_iSecond;
``
};
#endif
======================
#ifndef M_match
#define M_match
class Time;
class Match{
public:
void printTime(Time &t);
};
#endif
==========================
#include<iostream>
#include "Match.h"
#include"Time.h"
using namespace std;
void Match::printTime(Time &t){
cout<<t.m_iHour<<":"<< t.m_iMinute<<":"<<t.m_iSecond<<endl;
}
=======================
#include<iostream>
#include"Time.h"
#include"Match.h"
using namespace std;
int main() {
Time t(6,34,12);
Match m;
m.printTime(t);
}
遇到的问题:由于多个文件引用同一个头文件时,没有使用#ifndef和#endif就出现了redefinition的问题
解决办法:
文件中的#ifndef
头件的中的#ifndef,这是一个很关键的东西。比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。
还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的:
#ifndef <标识>
#define <标识>
......
#endif
<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h
#ifndef STDIO_H
#define STDIO_H
......
#endif
友元类
关键字:friend
声明了某个函数的友元类之后,此友元类可以访问到该类的所有属性和方法。
友元关系不可传递。
友元关系的单向性。
友元声明的形式(友元类/友元函数)以及数量(一个类可以有多个友元类)不受限制。
友元只是封装的补充。破坏了封装性,定向暴露,不建议使用。
注意:
1、在做练习题的时候有一个错误地方,就是构造函数的定义要加{};声明是不需要。
2、在A类中声明friend class B的意思是,B是A的友元类,B可以访问A的成员函数和属性。
static
在数据成员和成员函数之前加上static就变成了静态数据成员和静态成员函数。
普通数据成员和静态数据成员:
静态的依赖类。静态成员函数中,并不传入this指针,无法调用非静态数据成员,同时也不可以加上const关键字,但是可以调用静态成员或者全局成员。
注意事项:
静态数据成员必须单独初始化(在构造器之外),因为它并不随着对象的产生而产生,而是随着类的产生而产生。
静态成员函数不能调用非静态成员函数和非静态数据成员,后者可以调用前者。
运算符重载
给原有的运算符赋予新的意义。
成员函数的运算符重载:
#include<iostream>` `using namespace std;` `class Coor{` `public:` `Coor(int x,int y);` `Coor &operator-();` `int getX();` `int getY();` `private:` `int m_iX;` `int m_iY;` `};
=========================
#include"Coor.h"
Coor::Coor(int x,int y){
m_iX=x;
m_iY=y;
}
int Coor::getX(){
return m_iX;
}
int Coor::getY(){
return m_iY;
}
Coor &Coor::operator-(){
this->m_iX=-this->m_iX;
this->m_iY=-this->m_iY;
return *this;
}
=============================
#include"Coor.h"
#include<iostream>
using namespace std;
int main(){
Coor c(1,2);
cout<<c.getX()<<","<<c.getY()<<endl;
-c;
cout<<c.getX()<<","<<c.getY()<<endl;
}
友元函数的运算符重载:
#include<iostream>
using namespace std;
class Coor{
friend Coor &operator-(Coor &c);
public:
Coor(int x,int y);
int getX();
int getY();
private:
int m_iX;
int m_iY;
};
=======================
#include"Coor.h"
Coor::Coor(int x,int y){
m_iX=x;
m_iY=y;
}
int Coor::getX(){
return m_iX;
}
int Coor::getY(){
return m_iY;
}
Coor &operator-(Coor &c){
c.m_iX= -c.m_iX;
c.m_iY= -c.m_iY;
return c;
}
============================
#include"Coor.h"
#include<iostream>
using namespace std;
int main(){
Coor c(1,2);
cout<<c.getX()<<","<<c.getY()<<endl;
-c;
cout<<c.getX()<<","<<c.getY()<<endl; return 0;
}
++运算符重载,前置++和后置++用(int)来区分,带(int)是后置。
** 二元运算符的重载**
+号运算符可以用成员函数也可以用友元函数重载。
输出运算符''<<''不可以使用成员函数重载,必须使用友元函数重载。因为第一个对象必须是ostream对象。
索引运算符''[]''不可以使用友元函数重载,必须使用成员函数重载。因为第一个必须是该类自身的对象。
练习:
#include <iostream>
using namespace std;
/**
* 定义Coordinate类
* 数据成员:m_iX,m_iY
* 成员函数:构造函数
* 重载--运算符,重载+运算符
*/
class Coordinate
{
public:
Coordinate(int x, int y)
{
m_iX = x;
m_iY = y;
}
// 前置--运算符重载
Coordinate &operator--(){
m_iX--;
m_iY--;
}
// 后置--运算符重载
Coordinate &operator--(int){
m_iX--;
m_iY--;
}
// +号运算符重载
Coordinate operator+(Coordinate c1){
Coordinate temp(0,0);
temp.m_iX=this->m_iX+c1.m_iX;
temp.m_iY=this->m_iY+c1.m_iY;
return temp;
}
public:
int m_iX;
int m_iY;
};
int main(void)
{
Coordinate coor1(1, 3);
Coordinate coor2(2, 4);
Coordinate coor3(0, 0);
coor1--;
--coor2;
coor3 = coor1 + coor2;
cout << coor3.m_iX << endl;
cout << coor3.m_iY << endl;
return 0;
}
模板函数和模板类
模板函数
将类型作为参数。
关键字:template、typename、class
函数模板:
template <typename T,class C>
T max(T a,T b){
return (a>b)>a:b;}
通过函数模板产生的函数时模板函数。
函数模板与重载:函数模板只有在使用的时候,产生出来的函数之间才是重载的关系。
#include<iostream>
using namespace std;
template <typename T>
void display(T a){
cout<<a<<endl;
}
template <typename T,class S>
void display(T t, S s){
cout<<t<<endl;
cout<<s<<endl;
}
template <typename T ,int size>
void display(T a){
for(int i=0;i<size;i++){
cout<<a<<endl;
}
}
int main(){
display<int>(10);
display<double>(12.2);
display<int,double>(2,33.3);
display<int,10>(7);
return 0;
}
函数模板参数个数如果为0个,则没有必要使用函数模板
练习:
#include <iostream>
using namespace std;
/**
定义模板函数swapNum
实现功能:交换两个数的位置
*/
template <typename T,typename C>
void swap(T a,T b)
{
T temp = a;
a = b;
b = temp;
}
int main(void)
{
int x = 10;
int y = 20;
// 调用模板函数
swap<int,int>(x,y);
cout << "x = " << x << endl;
cout << "y = " << y << endl;
return 0;
}
类模板
只有数据类型不同。
关键字:template 、class
template
class M{
public:
...
void display();//在有类模板的条件下,类内的成员函数的定义每有什么不一样。
private:
T *m_pArr;//类内数据类型。
};
当成员函数在类外定义的时候:
template
void M
}
模板代码不能分离编译。不能将声明和定义在.h和.cpp中分开写。必须都写在.h中。
练习:
#include <iostream>
using namespace std;
/**
定义一个矩形类模板Rect
成员函数:calcArea()、calePerimeter()
数据成员:m_length、m_height
*/
template<class T>
class Rect
{
public:
Rect(T length,T height);
T calcArea();
T calePerimeter();
public:
T m_length;
T m_height;
};
/**
类属性赋值
*/
template<typename T>
Rect<T>::Rect(T length, T height)
{
m_length = length;
m_height = height;
}
/**
面积方法实现
*/
template<typename T>
T Rect<T>::calePerimeter()
{
return m_length * m_height;
}
/**
周长方法实现
*/
template<typename T>
T Rect<T>::calcArea()
{
return ( m_length + m_height) * 2;
}
int main(void)
{
Rect<int> rect(3, 6);
cout << rect.calcArea() << endl;
cout << rect.calePerimeter() << endl;
return 0;
}
标准模板类
C++标准模板库:STL(Standard Template Lib)
vector向量
本质时对数组的封装。vector的大小可以根据元素数量改变。
1、初始化:
2、常用方法:
3、例子:
#include<iostream>
#include<vector>
#include<list>
#include<map>
using namespace std;
int main(){
vector<int> vec;
vec.push_back(1);
vec.push_back(3);
vec.push_back(4);
for(int i=0;i<vec.size();i++){
cout<<vec[i]<<endl;
}
vector<int>::iterator itor=vec.begin();
for(;itor!=vec.end();itor++){
cout<<*itor<<endl;
}
cout<<vec.front()<<endl;
cout<<vec.back()<<endl;
vec.pop_back();
cout<<vec.size()<<endl;
return 0;
}
4、向量的遍历:for循环像遍历数组那样;或者使用迭代器iterator
list链表
list[i]不是实现,所以list的遍历可以用迭代器来实现。
#include<iostream>
#include<vector>
#include<list>
#include<map>
using namespace std;
int main(){
list<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(4);
list<int>::iterator i=l.begin();
for(;i!=l.end();i++){
cout<<*i<<endl;
}
return 0;
}
map映射
map中没有push_back,使用的时insert。使用迭代器的时候,因为是键值对,所以要分别输出key和value
#include<iostream>
#include<vector>
#include<list>
#include<map>
#include<string>
using namespace std;
int main(){
map<int,string> m;
pair<int,string>p1(1,"GOT7");
pair<int,string>p2(2,"Hello");
m.insert(p1);
m.insert(p2);
for(int i=0;i<m.size();i++){
cout<<m[i]<<endl;
}
map<int,string>::iterator it=m.begin();
for(;it!=m.end();it++){
cout<<it->first<<endl;
cout<<it->second<<endl;
}
return 0;
}
练习:
#include <vector>
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main(void)
{
// 使用vector存储数字:3、4、8、4
vector<int> vec;
vec.push_back(3);
vec.push_back(4);
vec.push_back(8);
vec.push_back(4);
//循环打印数字
for(int i=0;i<vec.size();i++){
cout<<vec[i]<<endl;
}
// 使用map来存储字符串键值对
map<string, string> m;
pair<string,string>p1("S","Shang Hai");
pair<string,string>p2("B","Bei Jing");
pair<string,string>p3("G","Guang Zhou");
m.insert(p1);
m.insert(p2);
m.insert(p3);
// 打印map中数据
map<string,string>::iterator it=m.begin();
for(;it!=m.end();it++){
cout<<it->first<<endl;
cout<<it->second<<endl;
}
return 0;
}
当map的key和value都是string类型的时候,好像只可以使用iterator来遍历。使用cout<<m[i]<<endl;是不可以遍历出来的。
标签:Coor,函数,05,int,C++,Time,include,模板,cout 来源: https://www.cnblogs.com/yunxiaoqian/p/14014646.html