C++(学习)2024.9.20
目录
C++面向对象的基础知识
this指针
概念
功能
1.类内调用成员
2.区分重名的成员变量和局部变量
3. 链式调用
static关键字
1.静态局部变量
2.静态成员变量
3.静态成员函数
4.单例设计模式
const关键字
1.const修饰成员函数
2.const修饰对象
3.const修饰成员变量
4.const修饰局部变量
运算符重载
友元
1.概念
2.友元函数
3.友元类
4.友元成员函数
C++面向对象的基础知识
this指针
概念
this指针是一个特殊的指针,指向当前类对象的首地址。
成员函数(包括构造函数和析构函数)中都有this指针,因此this指针只能在类内使用。实际上this指针指向的就是当前运行的成员函数所绑定的对象。
#include <iostream>
using namespace std;
class Test
{
public:
void test_this()
{
cout << this << endl;
}
};
int main()
{
Test t1;
cout << &t1 << endl;
t1.test_this();
Test t2;
cout << &t2 << endl;
t2.test_this();
Test *t3 = new Test;
cout << t3 << endl;
t3->test_this();
delete t3;
return 0;
}
功能
1.类内调用成员
成员(成员变量+成员函数)必须由对象调用。类中成员的调用都依赖于this指针的,通常由编译器自动添加。
#include <iostream>
using namespace std;
class Test
{
private:
string name;
public:
Test(string n)
{
this->name = n;
}
string get_name()
{
return this->name;
}
};
int main()
{
Test t1("zhangsan");
cout << t1.get_name() << endl;
return 0;
}
2.区分重名的成员变量和局部变量
#include <iostream>
using namespace std;
class Test
{
private:
string name;
public:
Test(string name)
{
this->name = name; // 通过this指针在函数体中进行区分
}
string get_name()
{
return name;
}
};
int main()
{
Test t1("zhangsan");
cout << t1.get_name() << endl;
return 0;
}
3. 链式调用
支持链式调用的成员函数特点:
●当一个成员函数的返回值是当前类型的引用时,往往表示这个函数支持链式调用。
●return后面是*this。
#include <iostream>
using namespace std;
class Test
{
private:
int val = 0;
public:
Test &add(int i)
{
val += i;
return *this;
}
int get_val()
{
return val;
}
};
int main()
{
Test t1;
t1.add(1);
t1.add(2);
t1.add(100);
cout << t1.get_val() << endl; // 103
// 链式调用
Test t2;
cout << t2.add(2).add(3).add(200).get_val() << endl;
return 0;
}
static关键字
1.静态局部变量
使用static修饰局部变量,这样的变量就是静态局部变量。
静态局部变量在第一次调用时创建,直到程序结束后销毁,同一个类的所有对象共用这一份静态局部变量。
#include <iostream>
using namespace std;
class Test
{
public:
void func()
{
int a = 1;
static int b = 1;
cout << "a=" << ++a << " " << &a << endl;
cout << "b=" << ++b << " " << &b << endl;
}
};
int main()
{
Test t1;
t1.func();
t1.func();
t1.func();
Test t2;
t2.func();
Test *t3 = new Test;
t3->func();
return 0;
}
注意:a可能会在同一个内存地址反复创建销毁。
2.静态成员变量
使用static修饰成员变量,这样的变量就是静态成员变量。
需要在类内声明,类外初始化。
一个类的所有对象共用一份静态成员变量。虽然静态成员变量可以使用对象调用的,但是更建议直接使用类名调用。所以静态成员变量可以脱离对象使用,在程序开始运行时就开辟内存空间,程序执行结束后销毁。
更推荐使用类名直接调用,代码的可读性更高。
#include <iostream>
using namespace std;
class Test
{
public:
int a = 1;
static int b;
};
// 静态成员变量,类外初始化
int Test::b = 1;
int main()
{
cout << Test::b << &Test::b << endl;
Test t1;
cout << t1.a++ << &t1.a << endl;
cout << t1.b++ << &t1.b << endl;
cout << " --------------- " << endl;
Test t2;
cout << t2.a++ << &t2.a << endl;
cout << t2.b++ << &t2.b << endl;
return 0;
}
3.静态成员函数
使用static修饰成员函数,这样的函数就是静态成员函数。
与静态成员变量相似的有:
都可以通过类名直接调用,也可以通过对象进行调用,也可以脱离对象使用。
静态成员函数没有this指针,不能再静态成员函数中调用同类中其他非静态成员,但是静态成员函数可以调用静态成员。
#include <iostream>
using namespace std;
class Test
{
public:
void func0()
{
//func1(); // 非静态成员函数可以调用静态成员函数
cout << "非静态成员函数" << endl;
}
static void func1(Test &t)
{
Test t2;
t2.func0();
t.func0();
//func0(); // 错误 静态成员函数,不能调用非静态成员函数
cout << "静态成员函数1" << endl;
}
};
int main()
{
Test t1;
Test t;
t1.func1(t);
return 0;
}
静态成员函数内调用当前类的非静态成员需要通过参数将对象传递进来,也可以在函数内创建对象进行调用。
4.单例设计模式
设计模式是一套被反复使用、多人知晓、经过分类的、代码设计经验的总结。通常用于一些面向对象的语言,如:JAVA、C++、C#等。这里以一个简化版本的单例设计模式为例,讲解static的实际使用。
#include <iostream>
using namespace std;
class Singleton
{
private:
Singleton(){}
Singleton(const Singleton&);
static Singleton *instance; // 静态成员变量
public:
static Singleton* get_instance() // 静态成员函数
{
if(instance == NULL)
{
instance = new Singleton;
}
return instance;
}
static void delete_instance()
{
if(instance != NULL)
{
delete instance;
instance = NULL;
}
}
};
Singleton *Singleton::instance = NULL;
int main()
{
Singleton *s1 = Singleton::get_instance();
Singleton *s2 = Singleton::get_instance();
cout << s1 << endl;
cout << s2 << endl;
return 0;
}
const关键字
1.const修饰成员函数
const修饰的成员函数,表示常成员函数。
特性:
(1)可以调用成员变量,但是不能修改成员变量的值
(2)不能调用非const的修饰的成员函数,哪怕这个函数并没有修改成员变量。
建议只要成员函数不修改成员变量就使用const修饰,例如show、get等等。
#include <iostream>
using namespace std;
class Demo
{
private:
int a;
public:
Demo(int a)
{
this->a = a;
}
void func0()
{
cout << "hello" << endl;
}
int get_demo()const
{
return a;
}
void test()const // 常成员函数
{
//a++; // 错误 const修饰的成员函数,不能修改成员变量
cout << a << endl;
//func0(); // 错误,const修饰的成员函数,不能调用非const修饰的成员函数
get_demo();
}
};
int main()
{
Demo demo(1);
demo.test();
cout << demo.get_demo() << endl;
return 0;
}
2.const修饰对象
const修饰的对象被称为常量对象,这种对象的成员变量值无法被修改,也无法调用非const的成员函数。
#include <iostream>
using namespace std;
class Demo
{
private:
int a;
public:
int b = 20;
Demo(int a)
{
this->a = a;
}
void func0()
{
cout << "hello" << endl;
}
int get_demo()const
{
return a;
}
void test()const // 常成员函数
{
//a++; // 错误 const修饰的成员函数,不能修改成员变量
cout << a << endl;
//func0(); // 错误,const修饰的成员函数,不能调用非const修饰的成员函数
get_demo();
}
};
int main()
{
const Demo demo(1); //Demo const demo(1);
cout << demo.get_demo() << endl;
//demo.func0(); // 错误,const修饰对象,无法调用非const修饰的成员函数
demo.test();
cout << demo.b << endl;
//demo.b = 10; // 错误,const修饰的对象,无法修改成员变量
return 0;
}
3.const修饰成员变量
const修饰的成员变量为常成员变量,表示该成员变量的值无法被修改。
常成员变量有两种初始化方式:
(1)声明后直接赋值
(2)构造初始化列表
上述两种方式同时使用时,以构造初始化列表为准。
#include <iostream>
using namespace std;
class Demo
{
private:
const int a = 1;
const int b = 2;
const int c = 3;
public:
Demo(int a,int b,int c):a(a),b(b),c(c){}
void show()
{
cout << a << " " << b << " " << c << endl;
}
};
int main()
{
Demo d1(10,20,30);
d1.show();
return 0;
}
4.const修饰局部变量
const修饰局部变量,表示该局部变量不可被修改。 这种方式常用于引用参数。
#include <iostream>
using namespace std;
class Demo
{
private:
const int a = 1;
const int b = 2;
const int c = 3;
public:
Demo(int a,int b,int c):a(a),b(b),c(c){}
void show()
{
cout << a << " " << b << " " << c << endl;
}
void test(const int &a1)
{
a1++;
const int d = 10;
}
};
int main()
{
int a = 1;
Demo d1(10,20,30);
d1.show();
d1.test(a);
return 0;
}
运算符重载
友元
1.概念
类实现了数据的隐藏和封装,类的数据成员一般定义为私有成员,仅能通过类的成员函数才能读写。如果数据成员定义为公共的,则又破坏了封装性。但是再某些情况下,需要频繁的读写类的数据成员,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查都需要时间的开销,而影响程序的运行效率。
友元有三种实现方式:
1.友元函数
2.友元类
3.友元成员函数
友元在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,是的非成员函数能够访问类的私有成员,导致程序维护性变差,因此使用友元要慎重。
2.友元函数
友元函数不属于任何一个类,是一个类外的函数,但是需要在类内进行“声明”。虽然友元函数不是类中的函数,但是却可以访问类中的所有成员(包括私有成员)
#include <iostream>
using namespace std;
class Test
{
private:
int a;
public:
Test(int i):a(i){}
void show()
{
cout << a << " " << &a << endl;
}
// 友元函数,类内声明
friend void and_test(Test &t);
};
// 友元函数
void and_test(Test &t)
{
cout << ++t.a << " " << &t.a << endl;
}
int main()
{
Test t1(1);
and_test(t1);
t1.show();
return 0;
}
友元函数的使用注意以下几点:
1.友元函数没有this指针
2.友元函数的“声明”可以放置到类中的任何位置,不受权限修饰符的影响。
3.一个友元函数理论上可以访问多个类,只需要再各个类中分别“声明”。
3.友元类
当一个类成为了另一个类Test的朋友时,类Test的所有成员都可以被类B访问,此时类B就是类Test的友元类。
#include <iostream>
using namespace std;
class Test
{
private:
int a;
public:
Test(int i):a(i){}
void show()
{
cout << a << " " << &a << endl;
}
// 友元类,类内声明
friend class B;
};
class B
{
public:
void and_test(Test &t)
{
++t.a;
cout << t.a << " " << &t.a << endl;
}
void and_test1(Test &t)
{
cout << ++t.a << " " << &t.a << endl;
}
};
int main()
{
Test t1(1);
B b;
b.and_test(t1);
b.and_test1(t1);
t1.show();
return 0;
}
友元类的使用需要注意以下几点:
1.友元关系不能被继承
2.友元关系不具有交换性(比如:类B声明为类Test的友元,类B可以访问类Test中的成员,但是类Test不能访问类B中的私有成员,如果需要访问,需要将类Test声明成类B的友元)
互为友元代码,需要类内声明,类外实现。
#include <iostream>
using namespace std;
class Cat;
class Test
{
private:
int a;
public:
Test(int i):a(i){}
void test(Cat &c);
friend class Cat;
};
class Cat
{
private:
int b;
public:
Cat(int i):b(i){}
void test1(Test &t);
friend class Test;
};
void Test::test(Cat &c)
{
cout <<c.b<<endl;
}
void Cat::test1(Test &t)
{
cout <<t.a++<<endl;
}
int main()
{
Test t(44);
Cat c(12);
c.test1(t);
return 0;
}
4.友元成员函数
使类B中的成员函数成为类Test的友元成员函数,这样类B的该成员函数就可以访问类Test的所有成员了。
#include <iostream>
using namespace std;
// 第四步:声明被访问的类
class Test;
class B
{
public:
// 第二步:声明友元成员函数(类内声明,类外实现)
void and_test(Test &t);
};
class Test
{
private:
int a;
public:
Test(int i):a(i)
{
}
void show()
{
cout << a << " " << &a << endl;
}
// 友元成员函数,第一步:确定友元成员函数的格式并声明
friend void B::and_test(Test &t);
};
// 第三步:类外定义友元成员函数
void B::and_test(Test &t)
{
++t.a;
cout << t.a << " " << &t.a << endl;
}
int main()
{
Test t1(1);
B b;
b.and_test(t1);
t1.show();
return 0;
}