一、函数重载和默认参数
#include<stdio.h>
#include<iostream.h>
void func(int a=0,int b){//
printf("%d %d",a,b);
}
void func(string a,string b){
printf("%s %s",a,b);
}
//函数重载:函数名相同,但是函数参数以及返回类型有一个不同就可以发生函数重载
int main(){
func(1,2);
func("123","abc");
}
二、 内存空间管理(new,delete)
int main(){
int *p=new int;//申请一个int型空间
delete p;
char *p=new char[10];//申请10个char空间
delete [] p;
]
三、类和对象
类的申明
class A{
public:
A(){//构造函数
a=100;
}
A(int data):a(data){
};
~A(){//析构函数
}
void func(void);
private:
int a;
protect:
}
//类外申明函数
void A::func(void){
printf("%d",a);
}
浅拷贝和深拷贝
浅拷贝:单纯的文本赋值,默认构造函数就是浅拷贝
深拷贝:在堆区创建新的内存空间,再把数据赋值(主要是类中有指针数据时需要注意)、
#include<iostream>
#include<string>
using namespace std;
class persion{
public:
persion(){};
persion(int age,int height){
this->age=age;
*m_height=height;
}
persion(const persion &p){
age=p.age;
m_height=new int(*p.m_height);
}
~persion(){
if (m_height!=NULL)
{
delete m_height;
m_height=NULL;
}
};
private:
string name;
int age;
string number;
int* m_height;
};
void test(){
persion p1(10,160);
persion p2(p1);//如果采用浅拷贝的方式,
//那么在调用结束时会对m_height所指的内存空间进行重复的释放,从而报错、
//因此采用深拷贝方式,让p2这个对象中的m_height指向新的内存空间就不会出现上述问题,所以需要对拷贝函数重写
};
int main()
{
test();
}
静态成员
#include<iostream>
#include<string>
using namespace std;
class persion {
public:
/*
静态成员变量;
1.静态成员变量在类内申明,类外初始化(出了类定义就是类外)
2.所有对象共享同一个静态成员变量
3.静态成员变量也拥有访问权限
*/
static int age;
int number;
/*
静态成员函数:
1.所有对象共享同一个静态成员函数
2.静态成员函数只能调用静态成员变量,不能调用非静态变量
3.静态成员函数业也有访问权限
*/
static void fun() {
m_height = 100;
//number=10;因为静态成员函数是共享的,所以无法区分是哪一个对象调用非静态成员
}
private:
static int m_height;
};
int persion::age = 100;
int persion::m_height = 200;
void test() {
persion p1;
persion p2;
/*
p1.m_height p2.m_height这样是无法访问的(静态成员也有访问权限问题)
*/
p1.age = p2.age = 100;
p1.fun();
//静态成员变量还可以通过类名访问
int a = persion::age;
persion::fun();
};
int main()
{
test();
}
常成员
#include<iostream>
#include<stdio.h>
class A {
public:
A(int data) :b(data) {//常成员赋值
}
void func(void)const {
printf("%d", b);
//a = 100;常函数不能修改成员的值
}
private:
const int b;
int a;
};
友元
1.全局函数做友元
2.类做友元
3.成员函数做友元
成为友元后可以访问私有权限的数据
#include<iostream>
#include<string>
using namespace std;
class Buliding {
friend void visit(Buliding& buliding);//全局函数做友元
friend void GoodGay::gvisit();//成员函数做友元
//friend class GoodGay;//类做友元
public:
Buliding();
public:
string m_SittingRoom;
private:
string m_BedRoom;
};
Buliding::Buliding() {//构造函数在类外定义
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
};
class GoodGay {
public:
GoodGay();
void gvisit();
Buliding* buliding;
};
GoodGay::GoodGay() {
buliding = new Buliding;
}
void GoodGay::gvisit() {
cout << buliding->m_SittingRoom << endl;
cout << buliding->m_BedRoom << endl;
}
void visit(Buliding& buliding) {//全局函数
cout << buliding.m_SittingRoom << endl;
cout << buliding.m_BedRoom << endl;
}
int main()
{
Buliding bulid;
visit(bulid);
GoodGay gg;
gg.gvisit();
}
四、运算符重载
1.加号运算符重载
#include<iostream>
#include<string>
using namespace std;
class persion{
public:
persion(){
m_a=10;
m_b=20;
}
//1.成员函数实现运算符重载
// persion operator+(persion &p){
// persion temp;
// temp.m_a+=p.m_a;
// temp.m_b+=p.m_b;
// return temp;
// }
/*
persion persionADDpersion(persion &p){运算符重载的实质就是成员函数名的更换
persion temp;
temp.m_a+=p.m_a;
temp.m_b+=p.m_b;
return temp;
}
*/
int m_a;
int m_b;
};
// 2.全局函数的运算符重载
persion operator+(persion p1,persion p2){
persion temp;
temp.m_a=p1.m_a+p2.m_a;
temp.m_b=p1.m_b+p2.m_b;
return temp;
}
persion operator+(persion p1,int num){
persion temp;
temp.m_a=p1.m_a+num;
temp.m_b=p1.m_b+num;
return temp;
}
int main()
{
persion p1;
persion p2;
persion p3=p1+p2;
//成员函数实现运算符重载的实质
//persion p3=p1.operator+(p2);
//全局函数实现运算符重载的实质
//persion p3=operator+(p1,p2);
//运算符重载实质就是函数,因此可以发生函数重载
persion p4=p1+100;
}
2.左移运算符重载
#include<iostream>
#include<string>
using namespace std;
class persion{
friend ostream& operator<<(ostream& cout,persion &p1);//采用友元的方式访问私有权限数据
public:
persion(){
m_a=10;
m_b=20;
}
private:
int m_a;
int m_b;
};
//只能利用全局函数实现左移运算符的重载
ostream& operator<<(ostream& cout,persion &p1){//由于ostream这个类对象只能有一个,
//不能创建一个新的对象,因此全部采用引用的方式来进行传递
cout<<p1.m_a<<" "<<p1.m_b;
return cout;
}
int main()
{
persion p1;
cout<<p1<<endl;
}
3递增运算符重载
#include<iostream>
using namespace std;
class MyInteger{
friend ostream& operator<<(ostream& cout, MyInteger myinteger);
public:
MyInteger() {
m_a = 0;
}
//前置运算符重载
MyInteger& operator++() {
m_a++;
return *this;
}
//后置运算符重载
MyInteger operator++(int) {//利用int占位符来区分前置和后置,而且只能用int来区分
//先存储之前的结果
MyInteger temp;
temp = *this;//*this就是其本身
//++
m_a++;
//返回之前的结果
return temp;
}
private:
int m_a;
};
ostream& operator<<(ostream& cout, MyInteger myinteger) {
cout << myinteger.m_a;
return cout;
}
int main() {
MyInteger a;
cout << a << endl;
cout << ++a << endl;
cout << a++ << endl;
cout << a << endl;
}
4赋值运算符重载(深拷贝,浅拷贝问题)
#include<iostream>
using namespace std;
class persion {
public:
persion(int age) {
m_age = new int(age);
}
~persion() {
delete m_age;
}
persion& operator=(persion& p){//返回值为persion&,实现程序可以连=操作,
//先判断是否有数据开辟在堆空间
if (m_age != NULL) {
delete m_age;
}
m_age = new int(*p.m_age);
return *this;
}
int* m_age;
};
int main() {
persion p1(10);
persion p2(20);
persion p3(30);
p3=p2 = p1;
cout << *p1.m_age << endl;
cout << *p2.m_age << endl;
cout << *p3.m_age << endl;
}
关系运算符重载和上述差不多
5函数调用重载(仿函数)
#include<iostream>
using namespace std;
class myprintf {
public:
void operator()(string str) {
cout << str << endl;
}
};
class myadd {
public:
int operator()(int num1,int num2) {
return num1 + num2;
}
};
int main() {
myadd madd;
cout << madd(10, 20) << endl;//仿函数和普通函数调用差不多,仿函数就是对‘=’赋值运算符的重载
cout << myadd()(30, 40) << endl;//匿名函数调用,匿名函数对象创建(使用完一次就释放内存,对象不存在)
}
五、组合和继承
组合:将其他类作为自己的数据成员,调用其接口,但是无法添加新的功能
继承:public继承,继承其他类的成员和属性,可以根据成员添加新的功能,也就是创建更加高级的功能。
#include "arr.h"
#include <iostream>
using namespace std;
class ARRX:public ARR{//继承
public:
int ever(void)//添加求平均功能
{
int i = 0;
int sum = 0;
for(;i<tail; i++)
sum += data[i];
return sum/tail;
}
};
class Stuma{
public:
Stuma(){
}
~Stuma() { }
void savescore(int score)
{
scorearr.addtail(score);
}
int everscore(void)//组合调用新添加求平均功能
{
return scorearr.ever();
}
void showscore(void)
{
scorearr.show();
}
private:
//ARR scorearr;
ARRX scorearr;//组合
};
int main()
{
Stuma mmm;
mmm.savescore(23);
mmm.savescore(44);
mmm.savescore(55);
mmm.savescore(23);
mmm.showscore();
cout << mmm.everscore() <<endl;
}
六、多态
虚函数(virtual)
#include<string>
#include<stdio.h>
#include <iostream>
using namespace std;
class A {
public:
virtual~A() { cout << "A--------" << endl; }
virtual void show() {//虚函数
cout << "aaaaaa" << endl;
}
private:
int x;
int y;
};
class AX :public A {
public:
virtual ~AX() { cout << "AX-----" << endl; }
void show() {
cout << "AAAAAAA" << endl;
}
};
int main() {
AX a;
/*c++允许基类指针指向派生类对象*/
A* p = &a;
p->show();//没有虚函数请款结果为"aaaaaa",根据指针类型确定。添加虚函数的情况下,结果为:"AAAAAAA"
//派生类同名函数对基类函数进行了一个完全覆盖
AX* q = &a;
q->show(); //没有虚函数请款结果为"AAAAAAA"
/*虚析构函数*/
A* x = new AX;
delete x; //因为x是A基类指针,因此在释放内存时会导致只调用基类的析构函数,那么派生类的析构没有调用,造成内存的泄露
//因此在编程当中,养成基类的虚构函数变成纯虚构函数,这样派生类的虚构函数也会调用
}
多态应用(联合动态编程)
编写一个类,可以求多种图形的周长
#include<string>
#include<stdio.h>
#include <iostream>
using namespace std;
class shape {
public:
virtual double getC(void) {
return 0;
}
};
class Cir :public shape {
public:
Cir(double r) :ri(r) {}
double getC(void) {
return 2 * 3.14 * ri;
}
private:
double ri;
};
class Tir :public shape {
public:
Tir(double a, double b, double c) :e1(a), e2(b), e3(c) {}
double getC(void) {
return e1 + e2 + e3;
}
private:
double e1;
double e2;
double e3;
};
class Sqr :public shape {
public:
Sqr(double e) {
this->e = e;
}
double getC(void) {
return 4 * e;
}
private:
double e;
};
/*构造一个函数实现不同类型的图形周长的计算,并返回总周长*/
double countC(shape* arry[], int num) {
double sumC;
for (int i = 0; i < num; i++)
{
sumC += arry[i]->getC();
}
return sumC;
}
int main() {
Cir cir(2);
Tir tir(3, 4, 5);
Sqr sqr(6);
//多态的一种应用,基类构建同名函数,便于统一管理和拓展
shape* arry[] = { &cir,&tir,&sqr };
cout << countC(arry, 3);
}
七、异常
异常机制
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
//异常,类似c语言goto,如果执行出错进行跳转执行
class argexpect :public exception {//继承c++标准的异常处理类
public:
const char* what() const throw(){
return "arg err!";
}
};
int myatoi(const char* str) {
if (*str < '0' || *str>'9')
throw argexpect();
return atoi(str);
}
int main() {
try {//无异常执行
int data = myatoi("abcc");
cout << data;
}
catch (argexpect& e) {//出现异常,捕捉异常消息-消息类型 实例
cout << e.what();
}
}
强制类型转换
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
/*
强制类型转换:四种方式
reinterpret_cast
const_cast
static_cast
dynamic_cast
*/
class A {
public:
virtual void show() {
cout << "AAAAAAAA" << endl;
}
};
class B :public A {
public:
void show() {
cout << "BBBBBBB" << endl;
}
};
int main(void) {
#if 0
int a;
char* p = reinterpret_cast<char*>(&a);
//强制转换为char*类型,但是会有内存泄露的风险
#endif
#if 0
const int a = 1000;
int* p = const_cast<int*>(&a);
//用于const之间的强制转换,也会存在内存泄露风险
#endif // 0
#if 0
A a;
B &p = static_cast<B&>(a);
//用于继承之间的强制转换,但是派生类指向基类会有风险
#endif // 0
#if 1
try
{
A a;
B& p = dynamic_cast<B&>(a);
//动态强转提供检测机制,判断强转是否出现异常,使用这个强转类中必须要有虚函数
}
catch (const std::exception& e)
{
cout << e.what();
}
#endif // 1
}
自定义转换
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
/*自定义转换函数*/
class mytime {
public:
mytime(int a, int b, int c) :hour(a),min(b),sec(c){}
operator int() {//强制将时间转化为秒数
return sec + min * 60 + hour * 60 * 60;
}
private:
int hour;
int min;
int sec;
};
int main() {
mytime t(1,2,3);
int sec = int(t);
cout << sec;
}
八、模版
函数模版
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
//函数模版
template<typename T>
void myswap(T& a, T& b) {
T temp=a;
a = b;
b = temp;
cout << a << " " << b << endl;
}
void test(void) {
int a = 10, b = 20;
//1.自动推导类型
myswap(a, b);
//2.显示声明类型
myswap<int>(a, b);
}
int main() {
test();
}
函数模版实现选择排序
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
template<class T>
void myswap(T& a, T& b) {
T temp=a;
a = b;
b = temp;
}
//函数模版实现选择排序
template<class T>
void mysort(T a[], int len) {
for (int i = 0; i < len; i++)
{
int max = i;
for (int j = i+1; j < len ; j++) {
if (a[max] < a[j])max = j;
}
if (max != i) {
myswap(a[i], a[max]);
}
}
for (int i = 0; i < len; i++)
{
cout << a[i] << " ";
}
}
void test(void) {
int arry[] = { 1,4,5,2,6,12,74,8,9,34 };
int num = sizeof(arry)/sizeof(int);
mysort(arry, num);
}
int main() {
test();
}
notes:
1、普通函数能欧实现隐式类型转换
2.、函数模版 自动类型推导无法实现隐式类型转换
3、函数模版 显式申明可以实现隐式类型转换(建议使用这种)
4.普通函数和函数模版都可以调用时,优先调用普通函数
5.空模版参数列表可以强制调用函数模版
6.函数模版也可以发生函数重载
7.如果函数模版产生更好的匹配,则调用函数模版
函数模版局限
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
//函数模版的局限,对于特殊的数据结构无法处理
class persion {
public:
persion(string name, int age) {
this->name = name;
this->age = age;
}
string name;
int age;
};
template<class T>
bool myjudge(T& a, T& b) {
if (a == b) return true;
else return false;
}
//对于特殊数据结构进行具体实现
template<>bool myjudge(persion& a, persion& b) {
if (a.name == b.name && a.age == b.age)return true;
else return false;
}
void test(void) {
persion p1("zhangsan", 10);
persion p2("lisi", 25);
cout<<myjudge(p1, p2);
}
int main() {
test();
}
notes:学习使用别人封装好的模版才是重点
类模版
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
//函数模版的局限,对于特殊的数据结构无法处理
template<class NameType,class AgeType=int>
class persion {
public:
persion(NameType name, AgeType age) {
this->name = name;
this->age = age;
}
void show(void) {
cout << name << " " << age << endl;
}
NameType name;
AgeType age;
};
void test(void) {
persion<string>p1("zhangsan", 112);//类模版只能是显式申明调用,而不能像函数模版一样采用自动推导
}
int main() {
test();
}
类模版中的成员函数只有在调用阶段才创建
类模版对象做函数参数
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
//函数模版的局限,对于特殊的数据结构无法处理
template<class NameType,class AgeType>
class persion {
public:
persion(NameType name, AgeType age) {
this->name = name;
this->age = age;
}
void show(void) {
cout << name << " " << age << endl;
}
NameType name;
AgeType age;
};
//指定传入类型(一般采用这种方式)
void printPersion(persion<string, int>& p) {
p.show();
}
void test1(void) {
persion<string,int>p1("zhangsan", 112);//类模版只能是显式申明调用,而不能像函数模版一样采用自动推导
printPersion(p1);
}
//参数模版化
template<class T1,class T2>
void printPersion1(persion<T1, T2>& p) {
p.show();
cout << "T1 type" << typeid(T1).name << endl;
}
void test2(void) {
persion<string, int>p("lisi", 67);
printPersion1(p);
}
//整个类模版化
template<class T>
void printPersion3(T& p) {
p.show();
cout << "T type:" << typeid(T).name << endl;
}
void test3(void) {
persion<string, int>p("wanger", 98);
printPersion3(p);
}
int main() {
test1();
test2();
test3();
}
类模版与继承
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
/*类模版与继承:子类继承父类必须要指明父类的模版参数类型*/
template<class T>
class Base {
public:
T m;
};
class Son :public Base<int> {//必须指明父类T的类型
};
//如果想要灵活指定父类T的类型,子类也需要是变类模版
template<class T1,class T2>
class Son2 :public Base<T1> {
public:
Son2() {
cout << "T1 type:" << typeid(T1).name() << endl;
cout << "T2 type:" << typeid(T2).name() << endl;
}
T2 x;
};
void test(void) {
Son2<string, int>s;
}
int main() {
test();
}
类模版成员函数类外实现
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
/*类模版与继承:子类继承父类必须要指明父类的模版参数类型*/
template<class T1,class T2>
class persion {
public:
persion(T1 name, T2 age);
void show();
T1 m_name;
T2 m_age;
};
template <class T1,class T2>
persion<T1,T2>::persion(T1 name, T2 age) {
this->m_age = age;
this->m_name = name;
}
template<class T1,class T2>
void persion<T1, T2>::show(void) {
cout << "name:" << this->m_name << "age:" << this->m_age << endl;
}
void test(void) {
persion<string, int>p("zhansgan", 45);
}
int main() {
test();
}
类模版分文件编写
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
#include"persion.hpp"//类模版分文件编写解决:将.h和.cpp的文件写到一个文件,并以.hpp后缀命名
//template<class T1,class T2>
//class persion {
//public:
// persion(T1 name, T2 age);
// void show();
//
// T1 m_name;
// T2 m_age;
//
//};
//
//
//template <class T1,class T2>
//persion<T1,T2>::persion(T1 name, T2 age) {
// this->m_age = age;
// this->m_name = name;
//}
//
//
//template<class T1,class T2>
//void persion<T1, T2>::show(void) {
// cout << "name:" << this->m_name << "age:" << this->m_age << endl;
//}
void test(void) {
persion<string, int>p("zhansgan", 45);
}
int main() {
test();
}
类模版与友元(全局函数类外实现)
#include<string>
#include<stdio.h>
#include <iostream>
#include<stdlib.h>
#include<exception>
using namespace std;
//全局函数类外实现
//首先让编译器知道有个类模版
template<class t1,class t2>
class persion;
//第二,编译器知道全局函数的实现
template<class t1,class t2>
void printPersion2(persion<t1, t2>p) {
cout << p.m_name<<" "<<p.m_age;
}
template<class t1,class t2>
class persion {
friend void printPersion1(persion<t1, t2>p) {//全局函数类内实现
cout << "name:"<<p.m_name << "age:"<<p.m_age;
}
friend void printPersion2<>(persion<t1, t2>p);//注意这里需要添加模版空列表参数
public:
persion(t1 name, t2 age) {
this->m_age = age;
this->m_name = name;
}
private:
t1 m_name;
t2 m_age;
};
void test(void) {
persion<string, int>p("zhansgan", 45);
//printPersion1(p);
printPersion2(p);
}
int main() {
test();
}
九、STL标准模版库
容器 算法 迭代器
预备知识
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
void printfNum(int val) {
cout << val << " ";
}
int main() {
vector<int>num;
for (int i = 0; i < 10; i++)
{
num.push_back(i);
}
for (vector<int>::iterator it = num.begin(); it < num.end(); it++)//*it就代表<>中的内容,这里*it代表int
{
cout << *it << " ";
}
cout << endl;
for_each(num.begin(), num.end(), printfNum);//利用算法遍历
vector<vector<int>>nums;//容器嵌套
for ( int i = 0; i < 10; i++)
{
nums.push_back({ i,i + 1,i + 2 });
}
for (vector<vector<int>>::iterator it = nums.begin(); it <nums.end() ; it++)
{
for (vector<int>::iterator its = (*it).begin(); its < (*it).end(); its++)
{
cout << *its << " " ;
}
cout << endl;
}
}
1.string
2.vector
互换容器->swap(vec)
3.deque
双端数组,可以对头端也可以对尾端进行插入和删除的操作