1)
请问类中函数 const修饰的谁
把类中的成员函数 转换成全局函数
成员函数返回*this
2)
自定义数组类封装 申明 与实现分开写 具有以下函数
void arr_set(int n,int value);
int arr_get(int n);
int arr_len()
3)
为什么会有友元函数
友元类:
4)
运算符重载
可以进行运算符重载的符
【二元操作符】 + -
全局函数的运算符重载,private成员变量
成员函数的运算符重载,private成员变量
【一元运算符】
成员函数,全局函数
前置++ 后置++
前置-- 后置--
有元函数的正真使用场景:
返回引用类型,链式输出对象的信息
5)
【难点】运算符重载提高
等号=
中括号[],当左值,当右值
相等符号 ==
不等于 !=
6)作业:封装一个字符类,使用 << ,>>,!= ,==,=,
附:运算符结合方向:
1,请问类中函数 const修饰的谁?
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
class A
{
public:
//const的三种写法
//const void fun(int a,int b)
//void const fun(int a,int b)
//void fun(int a,int b) const
void fun(int a,int b) const
{
a = 100; //const 修饰的不是a
//this->a = 200; //编译提示:‘A::a’ in read-only object
}
private:
int a;
int b;
};
int main()
{
A a1;
return 0;
}
答案:
const的三种写法修饰的是this指针
const void fun(int a,int b)
void const fun(int a,int b)
void fun(int a,int b) const
this指针所指向的内存空间不能被修改
相当于 void fun(const A *this,int a,int b)
修改this指针本身的值,编译也不通过
把类中的成员函数 转换成全局函数
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
class A
{
public:
void fun()
{
cout << "a="<<this->a<<" b="<<this->b<< " in fun"<<endl;
}
A(int a=0,int b=0)
{
this->a = a;
this->b = b;
cout << "a="<<this->a<<" b="<<this->b<<" in init \n";
}
A add(A &a)
{
A t(this->a + a.a,this->b + a.b);
return t;
}
A (const A &obj)
{
cout << "in copy \n";
}
~A()
{
cout << "a= "<<a << " b="<<b <<" free\n";
}
public:
int a;
int b;
};
//把成员函数转成全局函数
A fun(A &a1,A &a2)
{
A a3;
return a3;
}
void fun1()
{
cout << "-------- in fun1 ------------------- \n";
A a1(1,2);
A a2(3,4);
A a3 = a1.add(a2); a3.fun();
}
void fun2()
{
cout << "-------- in fun2 ------------------- \n";
A a1(1,2);
A a2(3,4);
A a3(5,5); a3 = a1.add(a2); a3.fun();
}
int main()
{
fun1();
fun2();
return 0;
}
chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
-------- in fun1 -------------------
a=1 b=2 in init
a=3 b=4 in init
a=4 b=6 in init
a=4 b=6 in fun
a= 4 b=6 free
a= 3 b=4 free
a= 1 b=2 free
-------- in fun2 -------------------
a=1 b=2 in init
a=3 b=4 in init
a=5 b=5 in init
a=4 b=6 in init
a= 4 b=6 free
a=4 b=6 in fun
a= 4 b=6 free
a= 3 b=4 free
a= 1 b=2 free
成员函数返回*this
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
class A
{
public:
void fun()
{
cout << "a="<<this->a<<" b="<<this->b<< " in print"<<endl;
}
A(int a=0,int b=0)
{
this->a = a;
this->b = b;
cout << "a="<<this->a<<" b="<<this->b<<" in init \n";
}
//返回一个引用,相当于返回自身
A& add(A &a)
{
this->a += a.a,
this->b += a.b;
return *this;
}
A (const A &obj)
{
cout << "in copy \n";
}
~A()
{
cout << "a="<<a << " b="<<b <<" free\n";
}
public:
int a;
int b;
};
int main()
{
A a1(1,2);
A a2(3,4);
a1.add(a2); a1.fun();
return 0;
}
chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
a=1 b=2 in init
a=3 b=4 in init
a=4 b=6 in print
a=3 b=4 free
a=4 b=6 free
chunli@Linux:~/c++$
自定义数组类封装 具有以下函数
void arr_set(int n,int value);
int arr_get(int n);
int arr_len();
文件1:
chunli@Linux:~/c++$ cat my_arr.h
#pragma once
class Arr
{
public:
void arr_set(int n,int value);
int arr_get(int n);
int arr_len();
Arr(int n);
Arr(const Arr &boj);
~Arr();
private:
int len;
int *arr;
};
chunli@Linux:~/c++$
文件2:
chunli@Linux:~/c++$ cat my_arr.cpp
#include "my_arr.h"
#include <iostream>
using namespace std;
void Arr::arr_set(int n,int value)
{
this->arr[n] = value;
}
int Arr::arr_get(int n)
{
return this->arr[n];
}
int Arr::arr_len()
{
return this->len;
}
Arr::Arr(int n)
{
if(n<1)
{
len = 0;
arr = NULL;
}
else
{
this->len = n;
arr = new int [n];
cout << n <<" init ...\n";
}
}
Arr::Arr(const Arr &obj)
{
this->len = obj.len;
arr = new int [this->len];
for(int i = 0;i<this->len;i++)
{
this->arr[i] = obj.arr[i] + 1;
}
cout << this->len<<" copy ...\n";
}
Arr::~Arr()
{
if(arr != NULL)
{
cout << this->len<<" free ...\n";
delete [] arr;
len = 0;
}
}
chunli@Linux:~/c++$
文件3:
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
#include "my_arr.h"
#include <stdlib.h>
using namespace std;
int main()
{
Arr a1(20);
for(int i = 0;i<a1.arr_len();i++)
{
a1.arr_set(i,i);
}
for(int i = 0;i<a1.arr_len();i++)
{
cout << a1.arr_get(i) << " ";
}
cout << endl;
Arr a2 = a1; //等号操作,C++编译器会调用拷贝构造函数
for(int i = 0;i<a2.arr_len();i++)
{
cout << a2.arr_get(i) << " ";
}
cout << endl;
return 0;
}
编译运行:
chunli@Linux:~/c++$ g++ -g main.cpp my_arr.cpp && ./a.out
20 init ...
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 copy ...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
20 free ...
20 free ...
chunli@Linux:~/c++$
为什么会有友元函数?
在实现类之间数据共享时,减少系统开销,提高效率。
如果类A中的函数要访问类B中的成员(例如:智能指针类的实现),那么类A中该函数要是类B的友元函数。
具体来说:为了使其他类的成员函数直接访问该类的私有变量。
即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数。
实际上具体大概有下面两种情况需要使用友元函数:
(1)运算符重载的某些场合需要使用友元。
(2)两个类要共享数据的时候。
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
class A
{
public:
A(int a,int b)
{
this->a = a;
this->b = b;
}
private:
int a;
int b;
};
void fun(A *p)
{
//不能在类的外部访问私有属性
int n =p->a;
}
int main()
{
A a1(1,2);
fun(&a1);
return 0;
}
编译就报错:
chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
main.cpp: In function ‘void fun(A*)’:
main.cpp:13:6: error: ‘int A::a’ is private
int a;
^
把这个函数添加为友元函数就OK了
友元函数 与 位置没有关系
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
class A
{
friend void fun(A *p);
public:
A(int a,int b)
{
this->a = a;
this->b = b;
}
int get_a()
{
return this->a;
}
private:
int a;
int b;
};
void fun(A *p)
{
//不能在类的外部访问私有属性
p->a = 10;
int n =p->a;
cout << n << endl;
}
int main()
{
A a1(1,2);
fun(&a1);
cout << a1.get_a() << endl;
return 0;
}
chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
10
10
友元类:
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
class A
{
friend class B;
private:
int a;
};
class B
{
friend void fun(A *p);
public:
B(int a)
{
a1.a = a; //可以直接修改友元类的属性
}
int get_a()
{
return this->a1.a;可以直接修改友元类的属性
}
private:
int a;
A a1;
};
int main()
{
B b1(11);
cout << b1.get_a() << "\n";
return 0;
}
chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
11
chunli@Linux:~/c++$
运算符重载,初步
让两个类直接相加减
运算符重载本质是一个函数
约定operator关键字
C++编译器会自动去找运算符
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
class A
{
public:
A(int a,int b)
{
this->a = a;
this->b = b;
}
int printf()
{
cout <<a<<" "<<b<<endl;
}
int a;
int b;
};
A operator+(A &a,A &b)
{
cout << "Hello World \n";
A t(a.a+b.a,a.b+b.b);
return t;
}
int main()
{
A a1(1,1);
A a2(2,2);
A a3 = a1+a2;
a3.printf();
return 0;
}
chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
Hello World
3 3
chunli@Linux:~/c++$
可以进行运算符重载的符合
不可以进行运算符重载的符合
【二元操作符】成员函数的运算符重载
此时的成员变量还都是public的
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
using namespace std;
class A
{
public:
A operator+(A obj)
{
cout << "成员函数的 运算符重载 \n";
A t(this->a + obj.a +1,this->b + obj.b +1 );
return t;
}
A(int a,int b)
{
this->a = a;
this->b = b;
}
int printf()
{
cout <<a<<" "<<b<<endl;
}
int a;
int b;
};
int main()
{
A a1(1,1);
A a2(2,2);
A a3 = a1+a2;
a3.printf();
return 0;
}
chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
成员函数的 运算符重载
4 4
【二元操作符】全局函数的运算符重载
此时的成员变量都是private的
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
using namespace std;
class A
{
friend A operator+(A &a,A &b);
public:
A(int a,int b)
{
this->a = a;
this->b = b;
}
int printf()
{
cout <<a<<" "<<b<<endl;
}
private:
int a;
int b;
};
A operator+(A &a,A &b)
{
cout << "Hello World \n";
A t(a.a+b.a,a.b+b.b);
return t;
}
int main()
{
A a1(1,1);
A a2(2,2);
A a3 = a1+a2;
a3.printf();
return 0;
}
chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
Hello World
3 3
【二元操作符】成员函数的运算符重载
此时的成员变量都是private的
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
using namespace std;
class A
{
public:
A operator+(A obj)
{
cout << "成员函数的 运算符重载 \n";
A t(this->a + obj.a +1,this->b + obj.b +1 );
return t;
}
A(int a,int b)
{
this->a = a;
this->b = b;
}
int printf()
{
cout <<a<<" "<<b<<endl;
}
private:
int a;
int b;
};
int main()
{
A a1(1,1);
A a2(2,2);
A a3 = a1+a2;
a3.printf();
return 0;
}
chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
成员函数的 运算符重载
4 4
【一元运算符】前置++
全局函数 运算符重载
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
using namespace std;
class A
{
friend A& operator++(A &a);
public:
A(int a,int b)
{
this->a = a;
this->b = b;
}
int printf()
{
cout <<a<<" "<<b<<endl;
}
private:
int a;
int b;
};
A& operator++(A &a)
{
cout << "成员函数的 运算符重载 \n";
a.a++;
a.b++;
return a;
}
int main()
{
A a1(1,1);
++a1;
a1.printf();
return 0;
}
chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
成员函数的 运算符重载
2 2
【一元运算符】前置++
成员函数 运算符重载
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
using namespace std;
class A
{
public:
A& operator++()
{
cout << "成员函数的 运算符重载 \n";
this->a++;
this->b++;
return *this; //A& 需要返回一个实体,而不是指针
}
A(int a,int b)
{
this->a = a;
this->b = b;
}
int printf()
{
cout <<a<<" "<<b<<endl;
}
private:
int a;
int b;
};
int main()
{
A a1(1,1);
++a1;
a1.printf();
return 0;
}
chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
成员函数的 运算符重载
2 2
chunli@Linux:~/c++$
全局函数 成员函数
前置++ 后置++
前置-- 后置--
【注意】全局函数的声明 要与友元函数的声明一致
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
using namespace std;
class A
{
friend A& operator--(A &a);
friend A operator--(A &a,int);
public:
A& operator++()
{
cout << "前置++ 一元运算符重载 ";
this->a++;
this->b++;
return *this; //A& 需要返回一个实体,而不是指针
}
A operator++(int)
{
cout << "后置++ 一元 运算符重载 ";
A t = *this;
this->a++;
this->b++;
return t;
}
A(int a,int b)
{
this->a = a;
this->b = b;
}
void printf()
{
cout <<a<<" "<<b<<endl;
}
private:
int a;
int b;
};
A& operator--(A &t)
{
cout << "前置-- 一元运算符重载 ";
t.a--;
t.b--;
return t;
}
A operator--(A &from,int)
{
cout << "后置-- 一元 运算符重载 ";
A t(from);
from.a--;
from.b--;
return t;
}
int main()
{
A aa(5,6); A a1(aa++); a1.printf();
A ab(5,6); A a2(++ab); a2.printf();
A ac(5,6); A a3(ac--); a3.printf();
A ad(5,6); A a4(--ad); a4.printf();
return 0;
}
chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out
后置++ 一元 运算符重载 5 6
前置++ 一元运算符重载 6 7
后置-- 一元 运算符重载 5 6
前置-- 一元运算符重载 4 5
chunli@Linux:~/c++$
有元函数的正真使用场景:
使用cout输出一个自定义类的成员变量,必须修改ostream类源码
在拿不到iostream的源代码的情景下,只能使用友元函数
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
using namespace std;
class A
{
friend void operator<<(ostream &friend_ship,A &from);
public:
A(int a,int b)
{
this->a = a;
this->b = b;
}
void printf()
{
cout <<a<<" "<<b<<endl;
}
private:
int a;
int b;
};
void operator<<(ostream &friend_ship,A &from)
{
friend_ship << "友元函数的真正应用场景\n";
friend_ship << from.a << " " <<from.b<< endl;
}
int main()
{
A a(5,6);
cout << a;
return 0;
}
chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out
友元函数的真正应用场景
5 6
链式输出对象的信息 cout << a << a;
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
using namespace std;
class A
{
friend ostream & operator<<(ostream &friend_ship,A &from);
public:
A(int a,int b)
{
this->a = a;
this->b = b;
}
void printf()
{
cout <<a<<" "<<b<<endl;
}
private:
int a;
int b;
};
//链式输出 需要返回一个引用
// <<操作符是至左向右结合
ostream & operator<<(ostream &friend_ship,A &from)
{
friend_ship << "友元函数的真正应用场景\n";
friend_ship << from.a << " " <<from.b<< endl;
return friend_ship;
}
int main()
{
A a(5,6);
cout << a << a;
return 0;
}
chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out
友元函数的真正应用场景
5 6
友元函数的真正应用场景
5 6
运算符重载提高:1
等号 = 运算符重载: 支持链式操作
【难点】 释放之前的指针,返回一个引用
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
class Str
{
public:
Str(const char *p)
{
this->len = strlen(p);
this->p = (char*)malloc(this->len + 1);
strcpy(this->p,p);
this->p[len] = '\0';
cout << this->p << " init\n";
}
Str(const Str &from)
{
this->len = strlen(from.p);
this->p =(char*)malloc(this->len + 1);
strcpy(this->p,from.p);
this->p[this->len] = '\0';
cout << "in copy \n";
}
~Str()
{
if(this->p != NULL)
{
cout << this->p << " free\n";
free(this->p);
this->p = NULL;
this->len = 0;
}
}
Str& operator=(Str &from)
{
if(this->p != NULL)
{
free(this->p); //先把自己之前的指针释放掉
}
cout <<from.p<< " -> in = operator\n";
this->len = strlen(from.p);
this->p = (char*)malloc(this->len + 1);
strcpy(this->p,from.p);
this->p[len] = '\0';
return *this;
}
private:
char *p;
int len;
};
int main()
{
Str s1("Hello");
Str s2("Linux");
Str s3("Google");
s1 = s2 = s3; //对象的赋值操作s1 = s2 ,不会调用赋值构造函数
return 0;
}
chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out
Hello init
Linux init
Google init
Google -> in = operator
Google -> in = operator
Google free
Google free
Google free
中括号[]运算符重载,数组类的
【难点】:函数当右值,函数当左值
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
using namespace std;
class Arr
{
public:
Arr(int n)
{
this->len = n;
p = new int[n];
}
~Arr()
{
delete [] p;
}
int & operator[](int i)
{
return p[i];
}
int len;
int *p;
};
int main()
{
Arr a1(16);
for(int i = 0;i<a1.len;i++)
{
a1[i] = i * i;
}
for(int i = 0;i<a1.len;i++)
{
cout << a1[i] << " ";
}
cout << "\n";
return 0;
}
chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out
0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225
【强化数组类练习!】等号=运算符重载,中括号[]运算符重载
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
using namespace std;
class Arr
{
public:
Arr(int n)
{
this->len = n;
p = new int[n];
}
~Arr()
{
if(p != NULL)
{
delete [] p;
p = NULL;
}
}
int & operator[](int i)
{
return p[i];
}
Arr & operator=(Arr &from)
{
if(this->p != NULL)
{
delete [] p;
}
this->len = from.len;
this->p = new int[this->len];
for(int i=0;i<from.len;i++)
{
this->p[i] = from.p[i];
}
return *this;
}
void out()
{
for(int i = 0;i<this->len;i++)
{
cout << this->p[i] << "\t";
}
cout << "\n";
}
void init(int num)
{
for(int i = 0;i<this->len;i++)
{
this->p[i] = i + num;
}
}
int len;
int *p;
};
int main()
{
Arr a1(16); a1.init(1); a1.out();
Arr a2(10); a2.init(2); a2.out();
a1 = a2; a1.out();
return 0;
}
chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
2 3 4 5 6 7 8 9 10 11
2 3 4 5 6 7 8 9 10 11
数组的 相等== 运算操作符重载,不等于!= 操作符重载
chunli@Linux:~/c++$ cat main.cpp
#include <iostream>
using namespace std;
class Arr
{
public:
Arr(int n)
{
this->len = n;
p = new int[n];
}
~Arr()
{
if(p != NULL)
{
delete [] p;
p = NULL;
}
}
int & operator[](int i)
{
return p[i];
}
Arr & operator=(Arr &from)
{
if(this->p != NULL)
{
delete [] p;
}
this->len = from.len;
this->p = new int[this->len];
for(int i=0;i<from.len;i++)
{
this->p[i] = from.p[i];
}
return *this;
}
bool operator!=(Arr &from)
{
if(this->len != from.len)
{
return true;
}
for(int i = 0;i<from.len;i++)
{
if(this->p[i] != from.p[i])
{
return true;
}
}
return false;
}
bool operator==(Arr &from)
{
if(this->len != from.len)
{
return false;
}
for(int i = 0;i<from.len;i++)
{
if(this->p[i] != from.p[i])
{
return false;
}
}
return true;
}
void out()
{
for(int i = 0;i<this->len;i++)
{
cout << this->p[i] << "\t";
}
cout << "\n";
}
void init(int num)
{
for(int i = 0;i<this->len;i++)
{
this->p[i] = i + num;
}
}
int len;
int *p;
};
int main()
{
Arr a1(16); a1.init(1); a1.out();
Arr a2(10); a2.init(2); a2.out();
a1 = a2; a1.out();
Arr a3(10); a3.init(1);
Arr a4(10); a4.init(1);
if(a3 == a4)
{
cout << "a3 == a4 \n";
}
else
{
cout << "a3 != a4 \n";
}
a4.init(2); //修改a4数组的值
if(a3 != a4)
{
cout << "a3 != a4 \n";
}
else
{
cout << "a3 == a4 \n";
}
return 0;
}
chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
2 3 4 5 6 7 8 9 10 11
2 3 4 5 6 7 8 9 10 11
a3 == a4
a3 != a4
运算符结合方向:
转载于:https://blog.51cto.com/990487026/1794745