指针常量、常量指针、常量指针常量
1.需要了解
什么是指针的指向,什么是指针指向的值
- 指针的指向,就是指针变量中存储的内存地址,比如
int *p;,其中*p就是指向int整型的指针 - 指针指向的值,就是指针指向内存地址所代表的数据,比如
p=&num,其中&num就是内存地址中所存储的数据
2.指针常量
2.1理解
是指用一个 const 修饰一个int 类型常量的指针,所以 *p 的值不能修改,比如const int *p;
2.2怎么去看该指针的指向和指针指向的值呢?
- 因为 const 修饰的是一个指针,所以该指针的指向不能改变,比如
*p = 20;,这里20就是该指针的指向,指向20的地址 - 但是被该指针指向的值可以被修改,比如
p=#,这里p就可以获取到&num的值
2.3总结
- 指针本身的地址不可更改,但是指针指向的值可以被修改
3.常量指针
3.1理解
是指用一个 const 修饰一个int *类型的变量,所以 p 的值不能修改,比如 int *const p;
3.2怎么去看该指针的指向和指针指向的值呢?
- 因为是修饰的是一个变量,所以该指针的指向可以被改变,比如
*p = 20, - 但是该指针指向的值不能改变,比如
p = &num,这里p在指向一个地址后,就不能指向另一个地址了
3.3总结
- 指针本身的地址可以修改,但是指针指向的值可以被修改
4.常量指针常量
4.1理解
是指用两个const,一个const修饰变量,一个const修饰int 类型的指针,比如 const int* const p;
4.2怎么去看该指针的指向和指针指向的值呢?
- 因为是修饰了一个变量,也修饰了一个int类型的指针,所以该指针的指向不能被改变,比如
*p = 20, - 该指针指向的值也不能被改变,比如
p = &num,这里p在指向一个地址后,就不能指向另一个地址了
4.3总结
- 指针本身的地址不能修改,但是指针指向的值也不能修改
5.常函数
-
在成员函数后加 const 后称为函数为常函数
void showPerson() const{ this->name = "lisi"; } -
常函数内不可以修改成员属性
void showPerson() const{ //这里会报错 this->name = "lisi"; } -
成员属性声明时加关键字mutable后,在常函数中依然可以修改
void showPerson() const{ //现在就不会报错了 this->name = "lisi"; } mutable string name;
6.常对象
-
声明对象前加 const 称为常对象
const Person p;//常对象 -
常对象只能调用常函数
void showPerson() const{ cout << "常函数" << endl; } void infoPerson(){ cout << "非常函数" << endl; } p.showPerson(); //可以调用 p.infoPerson();//不可以调用
引用
1.引用必须初始化
2.引用在初始化后,不能改变,但是可以进行赋值
int a = 20;
int &b = a; //引用进行初始化
int c = 30;
&b = c; //不能改变引用后的值
b = c; //但是可以进行赋值
3.引用传递,形参修饰实参
//函数参数为&a、&b
void swap(int &a,int &b){
int temp = a;
a = b;
b = temp;
}
int x = 10;
int y = 20;
swap(x, y);
4.引用传递不要返回局部变量
int &test(){
int a = 10;
return a;
}
int &ref = test();
int &test(){
static int a = 10;
return a;
}
int &ref = test();
5.若函数做左值,则必须返回引用,使用static
int &test(){
static int a = 10;
return a;
}
test() = 200; //相当于返回的a 是200,不是10
6.常量引用(const),无法进行修改,只能读取
函数
1.默认参数
- 函数的形参列表中的形参是可以有默认值的
- 默认参数必须放在参数的末尾
- 若有传递参数的值,则参数会代替默认参数
- 若函数声明有默认参数,则函数实现就不能有默认参数
2.占位参数
返回值类型 函数名 (数据类型){}- 比如重载运算符时,可以使用到占位运算符
重载运算符
函数重载(参数类型、参数顺序、参数个数、参数被const修饰)
访问修饰符
- 公共权限,public,类内可以访问,类外可以访问
- 保护权限,protected,类内可以访问,类外不可以访问,子类可以访问父类中的保护内容
- 私有权限,private,类内可以访问,类外不可以访问,子类不可以访问父类中的私有内容
拷贝构造函数
1.根据创建完毕的对象来初始化新对象
class Person{
public:
string name;
Person (string name){
this->name = name;
}
Person (const Person &obj){
name = obj.name;
}
}
Person p1("zhangsan");
Person p2(p1);
2.值传递的方式给函数参数传值
void doWork(Person p){
}
void test(){
Person p;
doWork(p);
}
3.值方式返回局部对象
void doWork(){
Person p1;
return p1;
}
void test(){
Person p = doWorkd();
}
浅拷贝和深拷贝
Person(const Person &obj){
//浅拷贝实现
name = obj.name;
//深拷贝实现
name = new string(*obj.name);
}
this指针
-
当形参和成员变量同名时,可用this指针来区分
Person(string name){ this->name = name; } -
在类的非静态成员函数中返回对象本身,可以使用return *this
Person& updateName(Person &p){ this->name = p.name+"1"; return *this; } Person p1("zhangsan"); Person p2("lisi"); p2.updateName(p1).updateName(p1).updateName(p1);
友元(friend)
全局函数做友元
#include <iostream>
using namespace std;
class Person {
friend void showPerson(Person* person);
public:
string name;
Person(string name, int age) {
this->name = name;
this->age = age;
}
private:
int age;
};
void showPerson(Person* person) {
cout << "name = " << person->name << "age = " << person->age << endl;
}
int main(void) {
Person p("张三", 22);
//直接调用友元函数
showPerson(&p);
return 0;
}
类做友元
class Father {
};
class Person {
friend void showPerson(Person* person);
//可以访问Person类中的成员
friend class Father;
public:
string name;
Person(string name, int age) {
this->name = name;
this->age = age;
}
private:
int age;
};
成员函数做友元
#include <iostream>
using namespace std;
//预先声明
class Person;
class Father {
public:
//构造函数
Father();
Person* person;
// 访问Person中的私有成员
void showPersonInfo();
};
class Person {
// 声明友元函数,可以访问私有成员
friend void Father::showPersonInfo();
public:
string name;
Person(string name, int age) : name(name), age(age) {} // 使用初始化列表
private:
int age;
};
//初始化函数
Father::Father() {
person = new Person("zhangsan", 22);
}
void Father::showPersonInfo() {
if (person != nullptr) {
cout << "name = " << person->name << ", age = " << person->age << endl;
}
else {
cout << "Person pointer is null!" << endl;
}
}
int main(void) {
// 直接调用友元函数
Father father;
father.showPersonInfo();
return 0;
}
运算符重载
-
成员函数重载
类名 operator 运算符(const 类名& 参数名){ } -
全局函数重载
类名 operator 运算符(const 类名& 参数名1,const 类名& 参数名2){ }
| 可重载运算符 | 运算符类型 |
|---|---|
| 双目算术运算符 | + (加),-(减),*(乘),/(除),% (取模) |
| 关系运算符 | ==(等于),!= (不等于),< (小于),> (大于),<=(小于等于),>=(大于等于) |
| 逻辑运算符 | ||(逻辑或),&&(逻辑与),!(逻辑非) |
| 单目运算符 | + (正),-(负),*(指针),&(取地址) |
| 自增自减运算符 | ++(自增),–(自减) |
| 位运算符 | | (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移) |
| 赋值运算符 | =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>= |
| 空间申请与释放 | new, delete, new[ ] , delete[] |
| 其他运算符 | ()(函数调用),->(成员访问),,(逗号),[](下标) |
| 不可重载运算符 | 运算符类型 |
|---|---|
| 成员访问运算符 | . |
| 成员指针访问运算符 | .* ,->* |
| 域运算符 | :: |
| 长度运算符 | sizeof |
| 条件运算符 | ?: |
| 预处理符号 | # |
重载输出运算符
ostream& operator<<(ostream &cout, Person &p){
cout << "name = " << p.name;
return cout;
}
Person p;
p.name = "zhangsan";
cout << p << "hello" << endl;
重载递增/递减运算符
#include <iostream>
using namespace std;
class MyInteger {
public:
MyInteger() {
this->num = 0;
}
int num;
//重载前置++运算符
MyInteger& operator++() {
//先进行运算
this->num ++;
//再将自身返回
return *this;
}
//重载后置++运算符
MyInteger operator++(int) {
//先记录
MyInteger temp = *this;
//后递增
this->num++;
//再返回记录结果
return temp;
}
};
ostream& operator<<(ostream &cout, MyInteger myInt) {
cout << myInt.num;
return cout;
}
int main(void) {
MyInteger myInt;
cout << ++(++myInt) << endl;
MyInteger myInts;
cout << (myInts++) << endl;
cout << (myInts) << endl;
return 0;
}
重载赋值运算符
#include <iostream>
using namespace std;
class Person {
public:
Person(int age) {
this->age = new int(age);
}
int *age;
Person& operator=(Person &p) {
//编译器默认是浅拷贝,即this->age = age;
//采用深拷贝
if (this->age != NULL) {
delete this->age;
age = NULL;
}
this->age = new int(*p.age);
return *this;
}
};
int main(void) {
Person p1(10);
Person p2(20);
Person p3(30);
p3 = p2 = p1;
cout << "p1的年龄为:" << *p1.age << endl;
cout << "p2的年龄为:" << *p2.age << endl;
cout << "p3的年龄为:" << *p3.age << endl;
return 0;
}
重载关系运算符
#include <iostream>
using namespace std;
class Person {
public:
Person( string name,int age) {
this->age = age;
this->name = name;
}
int age;
string name;
bool operator== (Person &p) {
if (this->name == p.name && this->age == p.age) {
return true;
}
return false;
}
};
int main(void) {
Person p1("zs", 12);
Person p2("ls", 12);
if (p1 == p2) {
cout << "p1 == p2 " << endl;
}
else {
cout << "p1 != p2 " << endl;
}
return 0;
}
重载函数调用运算符(仿函数)
#include <iostream>
using namespace std;
class MyPrint {
public:
//重载函数调用运算符
void operator()(string test) {
cout << test << endl;
}
};
int main(void) {
MyPrint myPrint;
myPrint("111测试111");
return 0;
}
模板
1.可以直接用template <class type>
2.类模板不能自动推导类型
3.类模板可以指定默认参数
4.类模板的成员函数在调用时创建
class Person1
{
public:
void showPerson1()
{
cout << "Person1 show" << endl;
}
};
class Person2
{
public:
void showPerson2()
{
cout << "Person2 show" << endl;
}
};
template<class T>
class MyClass
{
public:
T obj;
//类模板中的成员函数,并不是一开始就创建的,而是在模板调用时再生成
void fun1() { obj.showPerson1(); }
void fun2() { obj.showPerson2(); }
};
void test01()
{
MyClass<Person1> m;
m.fun1();
//m.fun2();//编译会出错,说明函数调用才会去创建成员函数
}
int main() {
test01();
system("pause");
return 0;
}
5.类模板对象作函数参数
//1、指定传入的类型
void printPerson1(Person<string, int> &p)
{
p.showPerson();
}
void test01()
{
Person <string, int >p("孙悟空", 100);
printPerson1(p);
}
6.类模板对象参数模板化
//2、参数模板化
template <class T1, class T2>
void printPerson2(Person<T1, T2>&p)
{
p.showPerson();
cout << "T1的类型为: " << typeid(T1).name() << endl;
cout << "T2的类型为: " << typeid(T2).name() << endl;
}
void test02()
{
Person <string, int >p("猪八戒", 90);
printPerson2(p);
}
7.类模板对象类模板化
//3、整个类模板化
template<class T>
void printPerson3(T & p)
{
cout << "T的类型为: " << typeid(T).name() << endl;
p.showPerson();
}
void test03()
{
Person <string, int >p("唐僧", 30);
printPerson3(p);
}
8.类模板与继承
template<class T>
class Base
{
T m;
};
//class Son:public Base //错误,c++编译需要给子类分配内存,必须知道父类中T的类型才可以向下继承
class Son :public Base<int> //必须指定一个类型
{
};
void test01()
{
Son c;
}
//类模板继承类模板 ,可以用T2指定父类中的T类型
template<class T1, class T2>
class Son2 :public Base<T2>
{
public:
Son2()
{
cout << typeid(T1).name() << endl;
cout << typeid(T2).name() << endl;
}
};
void test02()
{
Son2<int, char> child1;
}
int main() {
test01();
test02();
system("pause");
return 0;
}
9.构造函数类外实现
#include <string>
//类模板中成员函数类外实现
template<class T1, class T2>
class Person {
public:
//成员函数类内声明
Person(T1 name, T2 age);
void showPerson();
public:
T1 m_Name;
T2 m_Age;
};
//构造函数 类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {
this->m_Name = name;
this->m_Age = age;
}
//成员函数 类外实现
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
cout << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl;
}
void test01()
{
Person<string, int> p("Tom", 20);
p.showPerson();
}
int main() {
test01();
system("pause");
return 0;
}
10.分文件编写类模板
-
将声明和实现写到同一个文件中,并更改后缀名为.hpp
#pragma once #include <iostream> using namespace std; #include <string> template<class T1, class T2> class Person { public: Person(T1 name, T2 age); void showPerson(); public: T1 m_Name; T2 m_Age; }; //构造函数 类外实现 template<class T1, class T2> Person<T1, T2>::Person(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; } //成员函数 类外实现 template<class T1, class T2> void Person<T1, T2>::showPerson() { cout << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl; } //将声明和实现写到一起,文件后缀名改为.hpp #include "person.hpp" void test() { Person<string, int> p("Tom", 10); p.showPerson(); }11类模板的友元函数
#include <string> //2、全局函数配合友元 类外实现 - 先做函数模板声明,下方在做函数模板定义,在做友元 template<class T1, class T2> class Person; //如果声明了函数模板,可以将实现写到后面,否则需要将实现体写到类的前面让编译器提前看到 //template<class T1, class T2> void printPerson2(Person<T1, T2> & p); template<class T1, class T2> void printPerson2(Person<T1, T2> & p) { cout << "类外实现 ---- 姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl; } template<class T1, class T2> class Person { //1、全局函数配合友元 类内实现 friend void printPerson(Person<T1, T2> & p) { cout << "姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl; } //全局函数配合友元 类外实现 friend void printPerson2<>(Person<T1, T2> & p); public: Person(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; } private: T1 m_Name; T2 m_Age; }; //1、全局函数在类内实现 void test01() { Person <string, int >p("Tom", 20); printPerson(p); } //2、全局函数在类外实现 void test02() { Person <string, int >p("Jerry", 30); printPerson2(p); } int main() { //test01(); test02(); system("pause"); return 0; }
1394

被折叠的 条评论
为什么被折叠?



