找回密码
 立即注册
搜索
热搜: 活动 交友
楼主: Ray

面向对象程序设计复习贴

[复制链接]

45

主题

142

回帖

5173

积分

版主

积分
5173
 楼主| 发表于 6-23-2026 13:17:36 | 显示全部楼层
指向常量的指针
指针本身可以修改(指向别处),但不能通过该指针修改所指向的值。
const char *ptr;      // 等价于 char const *ptr;


常量指针
指针的指向固定,不能再指向其他地址,但可以通过它修改指向的内容(如果内容不是 const)
char *const ptr = a;


快速记忆法
const 在 * 左边 → 指向的内容是常量(pointer to const)
const 在 * 右边 → 指针本身是常量(const pointer)
可以两边都加 const:const char *const ptr 指向和内容都不可改。

45

主题

142

回帖

5173

积分

版主

积分
5173
 楼主| 发表于 6-23-2026 13:54:08 | 显示全部楼层
Coupling⚓︎
耦合(coupling) 是指程序中不同单元之间的连接。如果两个类在很多细节上有互相依赖的关系,那么我们认为它们是紧密耦合的。


我们的目标是松弛这种耦合关系,因为这有助于我们在不阅读其他类的情况下理解一个类,以及在不影响其他类的情况下改变一个类,从而提升了可维护性。


松弛耦合的方法有:


回调 (call-back)
消息机制 (message mech)
Cohesion⚓︎
内聚(cohesion) 指的是单个单位负责的任务数量和多样性,这一概念适用于类和方法上。如果一个单元仅对一个逻辑逻辑任务负责,那我们称这个单元具有高度的内聚性。


方法的内聚:方法(函数)应该仅为一个定义良好的任务负责
类的内聚:类应该表示为单个良好定义的实体
我们的目标是增强内聚性,因为这有助于理解类或方法的作用,使用描述性的名称以及重用类或方法。


Responsibility-Driven Design⚓︎
每个类应该为自己操纵的数据负责,所以我们希望做到改变局部化(to localize change),即一次改变仅会影响到少量类,从而降低耦合,实现责任驱动的设计。


Refactoring⚓︎
我们在维护类的时候,经常会让类和方法的代码增多,所以在维护时往往需要重构(refactor) 代码,以维护代码的内聚性和低耦合。


在重构代码时,不要让重构改变了代码的其他地方或代码的功能
重构前后需要检查代码,确保没有地方是被破坏掉的

45

主题

142

回帖

5173

积分

版主

积分
5173
 楼主| 发表于 6-23-2026 23:52:58 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

45

主题

142

回帖

5173

积分

版主

积分
5173
 楼主| 发表于 6-23-2026 23:53:42 | 显示全部楼层



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

45

主题

142

回帖

5173

积分

版主

积分
5173
 楼主| 发表于 6-23-2026 23:54:17 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

45

主题

142

回帖

5173

积分

版主

积分
5173
 楼主| 发表于 6-23-2026 23:54:43 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

45

主题

142

回帖

5173

积分

版主

积分
5173
 楼主| 发表于 6-23-2026 23:55:06 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

45

主题

142

回帖

5173

积分

版主

积分
5173
 楼主| 发表于 6-23-2026 23:58:04 | 显示全部楼层
楼主目前了解了封装、多态和继承。但是了解并不深入。
也就是将学长们的笔记看了个七成熟。


现在打开了deepseek-v4的一组对话,上传了手头上有用的笔记以及历年试卷,准备和ds对话来巩固所学知识的同时让ds分析考情并且结合题目讲述知识点。

此所谓面向考试编程(Test-Oriented Programming)。

45

主题

142

回帖

5173

积分

版主

积分
5173
 楼主| 发表于 6-26-2026 14:08:55 | 显示全部楼层
这些题目的考察风格偏向细节与边界,常常把多个知识点糅合在一个程序里,让你在看似正确的代码中找出隐蔽错误或推导准确输出。下面按照 C++ 的学习顺序,重新梳理这些套路和陷阱。

函数重载与默认参数
重载的判定只看参数列表,与返回值无关。参数个数和类型相同、仅返回值不同的两个函数不构成重载,编译器会报错。
带默认参数的重载很容易引发二义性。比如一个无参函数和一个有默认参数的有参函数同时存在,调用 f() 时编译器无法选择。
许多人以为“返回值不同就能重载”,这是经典误解。类似陷阱还有:默认参数写在声明与定义中不一致、重载函数用于毫无相干的语义,以及重载运算符时忘记返回引用导致连续运算失败。

类与对象基础
构造函数和析构函数都没有返回值,析构函数不能带参数,因此一个类只能有一个析构函数,它不能被重载。
复制构造函数必须用引用传递。当类中有指针成员时,必须手工实现深拷贝,否则默认的浅拷贝会让两个对象的指针指向同一块内存,析构时重复释放导致崩溃。
派生类构造时,如果没有显式调用基类构造,基类部分会使用默认构造,可能让成员初始化为意想不到的值。
const 成员必须用初始化列表赋值,且之后不可修改。
创建对象数组要求类有默认构造函数;如果自定义了带参构造却没提供无参构造,new T[n] 就会失败。
类里的 const 成员函数和非 const 成员函数可以重载:const 对象只能调用 const 版本,非 const 对象优先调用非 const 版本。

继承与多态
只有通过基类的指针或引用调用虚函数,多态才会生效。如果用基类对象直接接收派生类对象,会发生对象切片,丢掉派生类特性。
派生类覆盖虚函数时,函数签名必须完全一致——函数名、参数列表、const 修饰符一个都不能差。一旦 const 不一致,就不再是覆盖,而变成隐藏,此时通过基类指针调用的仍是基类版本,多态失效。
强烈建议使用 override 关键字,让编译器帮你检查签名错误。
含有纯虚函数的类是抽象类,不能实例化。如果派生类没有实现所有纯虚函数,它仍然是抽象类。
静态成员函数没有 this 指针,因此不能是虚函数,也无法实现多态。
友元函数可以访问私有成员,但虚函数必须是成员函数。
派生类覆盖虚函数时可以省略 virtual,函数依然是虚的。
访问控制上,private 成员对派生类不可见,想让派生类直接访问但又对外隐藏,必须用 protected。

运算符重载
单目运算符重载为成员函数时不需要形参,重载为友元时需要一个形参。
后置自增必须有一个 int 占位参数以区别于前置版本,后置返回的是修改前的副本(按值返回),前置返回的是修改后的引用。
赋值运算符通常返回 *this 的引用,以支持连续赋值。
重载 operator+ 时,语法上允许返回任意类型,但习惯上返回类类型以便链式调用。题目可能会故意给出返回 int 的例子,它语法合法,但破坏了链式运算的习惯。
下标运算符常重载为普通引用和 const 引用两个版本,分别用于读写和只读。
不能重载的运算符是常考选择题:::、.、.*、?: 等。

模板与异常
类模板的成员函数在类外定义时,必须带上 template<typename T> 和 类名<T>::。
try-catch 必须搭配使用,throw 可以抛出任意类型的对象,catch 按类型匹配。异常对象可以是简单枚举值。
静态成员变量必须在类外单独定义,否则链接报错。静态成员函数不能是虚函数,也没有 this。

这套题的风格就是在细微处做文章:不断在函数签名、const 一致性、初始化顺序、默认构造、深拷贝、覆盖条件等容易被忽略的地方挖掘错误。很多代码看起来能运行,实际却藏了切片、隐藏或未定义行为。应对的关键是深刻理解编译器的匹配规则——重载决议、覆盖与隐藏的判定、访问权限检查。类似的坑还有:析构函数是否该写 virtual、基类指针删除派生对象是否安全、赋值运算符是否检查自赋值、移动构造与移动赋值、explicit 防止隐式转换、初始化列表与构造体内赋值的区别等。扎扎实实掌握这些底层规则,才能写出安全可靠的 C++ 代码。

45

主题

142

回帖

5173

积分

版主

积分
5173
 楼主| 发表于 6-26-2026 14:19:46 | 显示全部楼层
本帖最后由 Ray 于 6-26-2026 14:25 编辑

一道比较好的题目,实现了字符串类。
值得一提的是,如果赋值时传入其他字符串,而不是char数组指针,则需要先进行判断。
如果相等,直接return *this。否则会出现a=a的情况时,先将目标字符串清空,进而出错。


#include <iostream>
using namespace std;
class ERROR{};
class STRING
{
   char *m_pStr;
   int m_len;
public:
   STRING(char *str=NULL){
      if (str != NULL) {   
           m_len = strlen(str);
         m_pStr = @@;  
         strcpy(@@);   
      }
      else {
         m_len = 0;
         m_pStr = NULL;
      }
   }  
   @@ operator=(char *str)  
   {
      @@ m_pStr ;   
      m_len = strlen(str)+1;
      m_pStr = new char[m_len];
      strcpy(@@);
      return @@;  
   }

   bool operator==(STRING str) @@
   {
      return (@@(m_pStr, str.m_pStr)== 0);  
   }
   char operator [] (int i) @@
   {
      if (i<m_len && i>=0) return m_pStr;
      throw @@;
   }
   char& operator[](int i) @@
   {
       if (i<m_len && i>=0) return m_pStr;
       ERROR e;
       @@;  
   }
  @@ ostream& operator<<(ostream& out ,STRING s);
};
ostream& operator<<(ostream& out ,STRING s)     
{
   out << s.m_pStr;
   return out;  
}


int main()
{
   STRING s1,s2("HeLLO");
   int i;
   cin >> i;
   s1 = s2;
   if (s1 == s2) cout << "S1 == S2\n";
   s1[1] = s1[1] + 1;
   cout << s1 << endl;;


   @@{  
       if(s1>='a' && s1<='z') s1 =  s1 - 32;
       cout << s1 << endl;
   }
   @@(   ERROR& e)  
   {
      cout << "upperbound overflow";
   }
   return 0;
}

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|RealDevClub ( 沪ICP备2024093864号-1 )

GMT+8, 8-8-2026 12:21 , Processed in 0.061117 second(s), 27 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表