C++ 面向对象实验
有需要参考代码的可以直接去公众号拿源码~~
文章目录
实验1 编程环境的熟悉及简单 C++程序的编制
1.1 实验目的和要求
-
熟悉 VS2010 编程环境,编制简单 C++程序并运行,熟悉 C++的编辑、 编译、 连接、运行、断点调试等过程。
-
掌握 C++数据类型,熟悉如何定义和使用常量和变量,以及对它们赋值的方法。
-
学会使用 C++的有关算术运算符及表达式,特别是自加(++)和自减(–)运算符的使用。
-
分支和循环结构的使用
1.2 实验任务
1.2.1 任务一
(1)题目名称
功能需求:运行时显示"Menu: A(dd) D(elete) S(ort) Q(uit), Select one:"
提示
用户输入,A 表示增加,D 表示删除,S 表示排序,Q 表示退出,
输入为 A、 D、S 时分别提示"数据已经增加、删除、排序。"
输入为 Q 时程序结束。
按照上述功能需求写两个程序,分别使用if分支语句和switch
分支语句实现:
程序1要求:使用 if … else
语句进行判断,用 break
、continue
控制程序流程。
程序2要求:使用 switch
语句实现。
(2)构思过程(可用文字、流程图、UML图等方式表达)
(3)程序源码
程序1:
#include<iostream>
using namespace std;
int main() {
cout << "Menu: A(dd) D(elete) S(ort) Q(uit), Select one:" << endl;
char a;
while (true) {
cin >> a;
if (a == 'A')cout << "数据已经增加" << endl;
else if (a == 'D')cout << "数据已经删除" << endl;
else if (a == 'S')cout << "数据已经排序" << endl;
else if (a == 'Q')break;
else cout << "指令错误,请重新输入";
}
return 0;
}
程序2:
#include<iostream>
using namespace std;
int main() {
cout << "Menu: A(dd) D(elete) S(ort) Q(uit), Select one:" << endl;
char a;
do {
cin >> a;
switch (a) {
case 'A':
cout << "数据已经增加" << endl;
break;
case 'D':
cout << "数据已经删除" << endl;
break;
case 'S':
cout << "数据已经排序" << endl;
break;
case 'Q':
break;
default:
cout << "非法输入,请重新输入" << endl;
break;
}
} while (a != 'Q');
return 0;
}
1.2.2 任务二
(1)题目名称
找出2~10000之内的所有完全数。所谓完全数,即其各因子之和正好等于本身的数。如6=1+2+3,28=1+2+4+7+14,所以6,28都是完全数。
(2)构思过程(可用文字、流程图、UML图等方式表达)
两层循环,一层遍历2~10000的数,一层找到该数因子。
(3)程序源码
#include<iostream>
using namespace std;
int main() {
for (int a = 2; a < 10000; a++) {
int j = 0;
for (int i = 1; i <= a / 2; i++)
if (a % i == 0)
j += i;
if (j == a)cout << a << " ";
}
}
实验2 函数的应用
2.1 实验目的和要求
-
掌握函数声明、定义和调用的方法;
-
掌握函数递归调用的方法;
-
掌握重载函数的声明、定义和使用方法;
-
理解函数参数传递中传值与引用的区别。
2.2 实验任务
2.2.1 任务一
(1)题目名称
用递归方法编写函数 Fibonacci(斐波那契)级数:
Fn = Fn-1+Fn-2,F1=F2=1
并求出第二十六项的值
(2)构思过程(可用文字、流程图、UML图等方式表达)
1,1,2,3,5,8,13,21,34,55……
设计递归,第一项和第二项均为1,其他项为其前两项之和。
(3)程序源码
#include<iostream>
using namespace std;
int fib(int a) {
if (a == 1)return 1;
if (a == 2)return 1;
return fib(a - 1) + fib(a - 2);
}
int main() {
int a;
cin >> a;
cout << fib(a);
}
2.2.2 任务二
(1)题目名称
设计一函数,判断一整数是否为素数。并完成下列程序设计:
①编写求素数的函数,并用这个函数求 3-200 之间的所有素数
②在 4-200 之间,验证歌德巴赫猜想:任何一个充分大的偶数都可以表示为两个素数之和。输出 4=2+2 6=3+3 …… 200=3+197
注:素数又称质数,指在一个大于 1 的自然数中,除了 1 和此整数自身外,不能被其他自然数(不包括 0)整除的数
(2)构思过程(可用文字、流程图、UML图等方式表达)
写一个函数来判断是不是素数,只需遍历到该数的平方根即可
满足i
是质数且200- i
是质数即可
(3)1. 程序源码
#include<iostream>
#include<cmath>
using namespace std;
bool isSuShu(int a) {
if (a == 2)return true;
if (a == 3)return true;
if (a > 3) {
int i;
for (i = 2; i <= pow(a, 0.5); i++)
if (a % i == 0)
return false;
if (i >= pow(a, 0.5))
return true;
}
return false;
}
int main() {
for (int i = 3; i <= 200; i++) {
if (isSuShu(i))
cout << i << endl;
else continue;
}
}
2. 程序源码
#include<iostream>
using namespace std;
int Su(int x) {
if (x == 1)return 0;
if (x == 2)return 1;
for (int i = 2; i < x; i++)
if (x % i == 0)
return 0;
return 1;
}
int main() {
int n;
cin >> n;
for (int j = 2; j < n; j++) {
if (Su(j) && Su(n - j)) {
cout << j << "+" << n - j << "=" << n << endl;
break;
}
}
}
2.2.3 任务三
思考题:
比较值传递和引用传递的相同点和不同点。
答:值传递函数内无法改变传入变量的值,引用传递传递的是地址,函数内可以改变传入变量的值。
调用被重载的函数时,通过什么来区分被调用的是哪一个函数?
答:通过参数类型或参数个数来区分。
实验3 类与对象、构造与析构函数
3.1 实验目的和要求
1.掌握类的定义和使用。
2.掌握类的定义和对象的声明。
3.掌握具有不同访问属性的成员的访问方式。
4.深入体会构造函数、复制构造函数、析构函数的执行机制。
5.使用的 VC++的 debug 调试功能观察程序流程,跟踪观察类的构造函数、析构函数、 成员函数的执行顺序。
3.2 实验任务
3.2.1 任务一
(1)题目名称
设计一个用于人事管理的 People(人员)类。考虑到通用性,这里只抽象出所有类型 人员都具有的属性:number(编号)、sex(性别)、birthday(出生日期)、id(身份证号)等。
其中"出生日期"定义为一个"日期"类内嵌子对象。
用成员函数实现对人员信息 的录入和显示。
要求包括:构造函数和析构函数、拷贝构造函数、内联成员函数、带缺省形参值的成员函数 、聚集。
(2)构思过程(可用文字、流程图、UML图等方式表达)
做people
类和date
类,写出date
的构造函数和缺省构造函数,写出date
的析构函数,同理写完people
,在people
类中写一个内联函数,在主函数中录入信息实验。
(3)程序源码
#include <iostream>
using namespace std;
class Date {
public:
Date(int month, int day, int year) {
year = year;
month = month;
day = day;
}
Date(int month, int day) {
year = 2000;
month = month;
day = day;
}
Date();
~Date() {};
void show() const;
private:
int year{};
int month{};
int day{};
};
class People {
private:
int number, id;
bool sex;
Date birthday;
public:
People(int number, int id, bool sex, Date birthday);
People(People &p);
~People() {};
void getNumber() const;
void getSex() const;
void getId() const;
inline void setSex(bool sx) {
sex = sx;
};
void show();
};
void Date::show() const {
cout << "生日:" << year << "年" << month << "月" << day << "日" << endl;
}
Date::Date() {}
void People::show() {
People::getSex();
People::getId();
People::getNumber();
People::birthday.show();
}
void People::getId() const {
cout << id << endl;
}
void People::getNumber() const {
cout << number << endl;
}
void People::getSex() const {
if (sex == 0) cout << "女" << endl;
else cout << "男" << endl;
}
People::People(int number, int id, bool sex, Date birthday) {
People::number = number;
People::sex = sex;
People::id = id;
People::birthday = birthday;
}
People::People(People &p) {
id = p.id;
sex = p.sex;
birthday = p.birthday;
number = p.number;
}
int main() {
Date dd(15, 2);
People pp(456, 135132, 1, dd);
pp.setSex(false);
pp.show();
Date d(15, 2, 2001);
People p(123, 130031, 1, d);
p.show();
}
3.2.2 任务二
(1)题目名称
使用 VS2010 或 StarUML 工具的画出上述第(5)题的 UML 图
(4)运行结果(截图)
实验4 数据共享与保护
4.1 实验目的和要求
-
观察程序运行中变量的作用域、生存期。
-
学习类的静态成员的使用。
-
理解类的友元函数、友元类。
-
学习多文件结构在 C++程序中的使用。
4.2 实验任务
(1)题目名称
定义一个 Girl 类和一个 Boy 类,这两个类中都有表示姓名、年龄的私有成员变量,
都要定义构造函数、析构函数、输出成员变量信息的公有成员函数。
-
根据要求定义相应的类;
-
将 Girl 类作为 Boy 类的友元类,在 Girl 类的成员函数 visitboy(boy &)中访问 boy 类的私有成员,观察程序运行结果;
-
在 boy 类的某成员函数 visitgirl(girl &)中试图访问 girl 类的私有成员,观察编译器给
出的错误信息,理解友元的不可逆性;
-
主函数中正确定义两个类的对象,调用各自的成员函数实现相应的功能;
-
再将 boy 类作为 girl 类的友元类,在 boy 类的某成员函数 visistgirl(girl &)中访问 girl
类的私有成员,观察编译器给出的信息;
- 删除两个类中的函数
visitgirl(girl &)
,visitboy(boy &)
,定义一个顶层函数
visitboygirl(boy &,girl &)
,作为以上两个类的友元,通过调用该函数输出男孩和女孩的信息。
(2)构思过程(可用文字、流程图、UML图等方式表达)
先编写两个类,女孩为男孩的友元。女孩类能访问男孩类的私有成员,而友元不可逆,男孩无法访问女孩信息。定义函数为两个类的友元函数,便可同时访问两个类的私有成员。
(3)程序源码
#include <iostream>
#include <string>
using namespace std;
class Girl;
class Boy;
void visitboygirl(Girl &g, Boy &b);
class Boy {
public:
Boy() {
name = "小明";
age = 18;
}
Boy(string a, int b) {
name = a;
age = b;
}
~Boy() {};
void show();
void visitgirl(Girl &g);
friend void visitboygirl(Girl &g, Boy &b);
private:
int age;
string name;
};
class Girl {
public:
Girl() {
name = "小红";
age = 18;
}
Girl(string a, int b) {
name = a;
age = b;
}
~Girl() {};
void show();
void visitboy(Boy &b);
friend void visitboygirl(Girl &g, Boy &b);
private:
int age;
string name;
};
void Girl::show() {
cout << "女孩姓名:" << name << "\t年龄:" << age << endl;
}
void Boy::show() {
cout << "访问男孩姓名:" << name << "\t年龄:" << age << endl;
}
//void Boy::visitgirl(Girl &g) {
// cout << "访问女孩姓名:" << g.name << "\t年龄:" << g.age << endl;
//}
//void Girl::visitboy(Boy &b) {
// cout << "访问男孩姓名:" << b.name << "\t年龄:" << b.age << endl;
//}
void visitboygirl(Girl &g, Boy &b) {
cout << "访问女孩姓名:" << g.name << "\t年龄:" << g.age << endl;
cout << "访问男孩姓名:" << b.name << "\t年龄:" << b.age << endl;
}
int main() {
Girl g;
Boy b;
g.show();
b.show();
visitboygirl(g, b);
return 0;
}
实验5 数组、指针与字符串
5.1 实验目的和要求
-
学习使用数组。
-
掌握指针的使用方法,体会运算符&、*的不同作用。
-
学习字符串数据的组织和处理。
-
练习通过动态分配内存实现动态数组,并体会指针在其中的作用。
-
分别使用字符数组和标准 C++库练习处理字符串的方法。
5.2 实验任务
(1)题目名称
编写 C++程序完成以下功能:
用类来实现矩阵,定义一个矩阵的类,属性包括:
矩阵大小,用 lines, rows(行、列来表示);
存贮矩阵的数组指针,根据矩阵大小动态申请(new)。
矩阵类的方法包括:
构造函数:参数是矩阵大小,需要动态申请存贮矩阵的数组;
析构函数:需要释放矩阵的数组指针;
拷贝构造函数:需要申请和复制数组(深复制);
输入函数:可以从 cin 中输入矩阵元素;
输出函数:将矩阵格式化输出到 cout;
矩阵相加函数:实现两个矩阵相加的功能,结果保存在另一个矩阵里,但必须矩阵
大小相同;
矩阵相减的函数:实现两个矩阵相减的功能,结果保存在另一个矩阵里,但必须矩阵大小相同。
(2)构思过程(可用文字、流程图、UML图等方式表达)
定义这样的一个矩阵类
重载+,-,=运算符,析构函数中要注意释放堆区内存,因为又堆区数据,所以要做深拷贝的拷贝构造函数,setju
用来读取矩阵,getju
用来输出矩阵。
(3)程序源码
#include <iostream>
using namespace std;
class juZhen {
int num, *p, lines, rows;
public:
juZhen();
~juZhen();
juZhen(int l, int r);
juZhen(const juZhen &j);
void setJu();
void getJu();
juZhen operator+(const juZhen &j);
juZhen operator-(const juZhen &j);
juZhen operator=(const juZhen &j);
};
juZhen::juZhen() {
}
juZhen::juZhen(int l, int r) {
lines = l;
rows = r;
num = r * l;
p = new int[num];
}
juZhen juZhen::operator+(const juZhen &j) {
for (int i = 0; i < j.num; ++i) {
this->p[i] = j.p[i] + this->p[i];
}
return *this;
}
juZhen juZhen::operator-(const juZhen &j) {
for (int i = 0; i < j.num; ++i) {
this->p[i] = j.p[i] - this->p[i];
}
return *this;
}
juZhen juZhen::operator=(const juZhen &j) {
for (int i = 0; i < j.lines * j.rows; ++i) {
this->p[i] = j.p[i];
}
return *this;
}
juZhen::juZhen(const juZhen &j) {
this->lines = j.lines;
this->rows = j.rows;
this->p = new int[lines * rows];
for (int i = 0; i < j.num; ++i) {
p[i] = j.p[i];
}
}
void juZhen::setJu() {
for (int i = 0; i < lines; ++i) {
for (int j = i * rows; j < (i + 1) * rows; ++j) {
cin >> p[j];
}
}
}
void juZhen::getJu() {
for (int i = 0; i < lines; ++i) {
for (int j = i * rows; j < (i + 1) * rows; ++j) {
cout << p[j] << " ";
}
cout << endl;
}
}
juZhen::~juZhen() {
cout << "juZhen析构函数被调用" << endl;
delete[]p;
}
int main() {
juZhen a(3, 3);
cout << "请输入a矩阵" << endl;
a.setJu();
juZhen b(3, 3);
cout << "请输入b矩阵" << endl;
b.setJu();
juZhen c = a + b;
c.getJu();
juZhen *x = new juZhen(2, 2);
cout << "请输入x矩阵" << endl;
x->setJu();
juZhen *y = new juZhen(2, 2);
cout << "请输入y矩阵" << endl;
y->setJu();
juZhen *z = new juZhen(2, 2);
*z = *x - *y;
z->getJu();
delete x;
delete y;
delete z;
}
实验6 类的继承与派生
6.1 实验目的和要求
-
从深层次上理解继承与派生的关系
-
掌握不同继承方式下,从派生类/对象内部和外部对基类成员的访问控制权限。
-
掌握单继承和多继承的使用方法,尤其是派生类构造函数的声明方式。
-
掌握继承与派生下构造函数与析构函数的调用顺序。
-
理解“类型兼容”原则
-
学习利用虚基类解决二义性问题。
6.2 实验任务
(1)题目名称
编写 C++程序,以完成以下功能(具体的数据成员、函数成员,请自主定义):
(1)声明一个基类 Shape(形状),其中包含一个方法来计算面积;
(2)从 Shape 派生两个类:矩形类(Rectangle)和圆形类(Circle);
(3)从 Rectangle 类派生正方形类 Square;
(4)分别实现派生类构造函数、析构函数及其它功能的成员函数;
(5)创建各派生类的对象,观察构造函数、析构函数的调用次序;
(6)计算不同对象的面积。
将 1 中 Shape
基类计算面积的方法定义为虚函数,比较与【形状(一)】程序的差异,体验其优点。
(2)构思过程(可用文字、流程图、UML图等方式表达)
重载各自类中计算面积的函数,注意各个类中是否需要无参构造函数
要找到子类之间的差异在哪(计算面积),然后在子类中写相应的变动。
(3)程序源码1
#include <iostream>
#include <cmath>
using namespace std;
class Shape {
public:
Shape(double a, double b) {
chang = a;
kuan = b;
cout << "shape构造函数被调用" << endl;
}
virtual ~Shape() {
cout << "Shape析构函数被调用" << endl;
}
double cal() const {
return chang * kuan;
}
void getArea() const {
cout << "面积为:" << cal() << endl;
}
private:
double kuan, chang;
};
class Circle : public Shape {
public:
Circle(double a) : Shape(a, a) {
banjing = a;
cout << "Circle构造函数被调用" << endl;
}
~Circle() {
cout << "circle析构函数被调用" << endl;
}
double cal() const {
return banjing * banjing * 3.14;
}
void getArea();
private:
double banjing;
};
class Rectangle : public Shape {
public:
Rectangle() : Shape(0, 0) {}
Rectangle(double a, double b) : Shape(a, b) {
kuan = a;
chang = b;
cout << "Rectangle构造函数被调用" << endl;
}
~Rectangle() {
cout << "rectangle析构函数被调用" << endl;
}
double cal() const {
return chang * kuan;
}
void getArea();
private:
double kuan, chang;
};
class Square : public Rectangle {
public:
Square(double a) : Rectangle(a, a) {
bianchang = a;
cout << "Square构造函数被调用" << endl;
}
~Square() {
cout << "square析构函数被调用" << endl;
}
double cal() const {
return bianchang * bianchang;
}
void getArea();
private:
double bianchang;
};
void Rectangle::getArea() {
cout << "面积为:" << Rectangle::cal() << endl;
}
void Circle::getArea() {
cout << "面积为:" << Circle::cal() << endl;
}
void Square::getArea() {
cout << "面积为:" << Square::cal() << endl;
}
int main() {
Rectangle r(10, 20);
r.getArea();
Square s(10);
s.getArea();
Circle c(10);
c.getArea();
return 0;
}
(3)程序源码2
#include <iostream>
#include <cmath>
using namespace std;
class Shape {
public:
Shape(double a, double b) {
chang = a;
kuan = b;
cout << "shape构造函数被调用" << endl;
}
virtual ~Shape() {
cout << "Shape析构函数被调用" << endl;
}
virtual double cal() {
return chang * kuan;
}
virtual void getArea() {
cout << "面积为:" << cal() << endl;
}
private:
double kuan, chang;
};
class Circle : public Shape {
public:
Circle(double a) : Shape(a, a) {
banjing = a;
cout << "Circle构造函数被调用" << endl;
}
~Circle() {
cout << "circle析构函数被调用" << endl;
}
double cal() {
return banjing * banjing * 3.14;
}
/* void getArea();*/
private:
double banjing;
};
class Rectangle : public Shape {
public:
Rectangle() : Shape(0, 0) {}
Rectangle(double a, double b) : Shape(a, b) {
kuan = a;
chang = b;
cout << "Rectangle构造函数被调用" << endl;
}
~Rectangle() {
cout << "rectangle析构函数被调用" << endl;
}
/*void getArea();*/
double cal() {
return chang * kuan;
}
private:
double kuan, chang;
};
class Square : public Rectangle {
public:
Square(double a) : Rectangle(a, a) {
bianchang = a;
cout << "Square构造函数被调用" << endl;
}
~Square() {
cout << "square析构函数被调用" << endl;
}
//void getArea();
double cal() {
return bianchang * bianchang;
}
private:
double bianchang;
};
//
//void Rectangle::getArea() {
// cout << "面积为:" << mj << endl;
//}
//
//void Circle::getArea() {
// cout << "面积为:" << mj << endl;
//}
//void Square::getArea() {
// cout << "面积为:" << mj << endl;
//}
int main() {
Rectangle r(10, 20);
Shape *p[3];
p[0] = &r;
p[0]->getArea();
Square s(10);
p[1] = &s;
p[1]->getArea();
Circle c(10);
p[2] = &c;
p[2]->getArea();
return 0;
}
实验7 多态性
7.1 实验目的和要求
-
掌握将运算符重载为成员函数与非成员函数的区别。
-
掌握静态编联与动态联编的概念、区别及实现方式。
-
掌握利用虚函数实现动态多态的方法。
-
掌握利用纯虚函数与抽象类实现动态多态的方法。
7.2 实验任务
(1)题目名称
定义一个基类为哺乳动物类 mammal
,其中有数据成员年龄、重量、品种,有成员函数 move()、speak()、eat()等,以此表示动物的行为。由这个基类派生出狗、猫、马、猪等 哺乳动物,它们都有各自的行为。编程分别使各个动物表现出不同的行为。编程思想:
-
为实现动态联编,首先建立
Mammal
抽象类,以此抽象类作为基类,派生 dog、cat、 horse、pig 类。其中Mammal
类数据员有(姓名)name 、(年龄)age、(重量)weight。成员函数 move()、eat()、speak(),定义为纯虚函数:另一个成员函数display()
,声明为虚函数。 -
建立各个派生类 dog、cat、horse、pig。然后建立构造函数为其初始化。再定义函数
move()
、speak()
、eat()
等。 -
main()
函数中建立指向Mammal
的指针数组,并为各派生类初始化。把指针数组分别指向各 个派生类。设计一个循环来显示派生类对象的信息。
(2)构思过程(可用文字、流程图、UML图等方式表达)
建立mammal
抽象类,各个派生类建立构造函数进行初始化,主函数中建立指针数组,用循环在主函数中显示派生类对象信息
(3)程序源码
#include<iostream>
#include<string>
using namespace std;
class mammal {
int age;
int weight;
string name;
public:
mammal() {
weight = 0;
age = 0;
name = "无";
}
mammal(string s, int a, int b) {
name = s;
age = a;
weight = b;
}
virtual~mammal() {
cout << "mammal析构函数被调用" << endl;
}
virtual void display() {
cout << "种类:" << name << "年龄:" << age << "体重:" << weight << endl;
}
virtual void eat() = 0;
virtual void move() = 0;
virtual void speak() = 0;
};
class Cat : public mammal {
public:
Cat() : mammal("无", 0, 0) {}
Cat(string s, int a, int b) : mammal(s, a, b) {}
public:
void move() { cout << "猫动了" << endl; }
void speak() { cout << "喵喵喵" << endl; }
void eat() { cout << "猫吃了" << endl; }
};
class Dog : public mammal {
public:
Dog() : mammal("无", 0, 0) {}
Dog(string s, int a, int b) : mammal(s, a, b) {}
public:
void move() { cout << "狗动了" << endl; }
void speak() { cout << "汪汪汪" << endl; }
void eat() { cout << "狗吃了" << endl; }
};
class Pig : public mammal {
public:
Pig() : mammal("无", 0, 0) {}
Pig(string s, int a, int b) : mammal(s, a, b) {}
public:
void move() { cout << "猪动了" << endl; }
void speak() { cout << "哼哼哼" << endl; }
void eat() { cout << "猪吃了" << endl; }
};
class Horse : public mammal {
public:
Horse() : mammal("无", 0, 0) {}
Horse(string s, int a, int b) : mammal(s, a, b) {}
public:
void move() { cout << "马动了" << endl; }
void speak() { cout << "稀溜溜" << endl; }
void eat() { cout << "马吃了" << endl; }
};
int main() {
mammal *a[4];
Cat cat("猫", 10, 10);
Dog dog("狗", 20, 20);
Horse horse("马", 30, 30);
Pig pig("猪", 40, 40);
for (int i = 0; i < 4; i++) {
switch (i) {
case 1:
a[i] = &cat;
break;
case 2:
a[i] = &dog;
break;
case 3:
a[i] = &pig;
break;
case 0:
a[i] = &horse;
break;
}
a[i]->display();
a[i]->eat();
a[i]->speak();
a[i]->move();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效