C++中的易混点2

C++中的易混点

一、前言

还有4天,今天继续回顾易混的点。。。

二、易混的点

多态性的含义

误解:多态性指的是对象的状态会根据运行时要求自动变化

正解同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。

阐释 :多态是针对对象没错,但是前提是针对同一个消息/操作
*

在除法运算中,保证精度

如何保证精度呢?只是将承载变量定义为floatdouble就能实现了吗?答案当然是No!!!。我指条明路:
*

复制代码
```cpp
float c = 5.0f / 4;
```
复制代码
```cpp
float c = 5 / 0.4f;
```
复制代码
```cpp
float c = 5.0 / 4;
```
复制代码
```cpp
float c =(float)5 / 4;
```
不同继承下的成员访问权限
列表示继承方式 public protected private
public public protected 不可访问
protected protected protected 不可访问
private private private 不可访问

记了很多遍了,但今天再看,又是"熟悉的陌生人"...
*

关于指针的运算
cpp 复制代码
int a[10]={1,2,3,4,5,6,7,8,9,10};
*p=a;
// 第一种
*p+=9;					// 先对p解引用得到具体的值------a[0],然后 + 9,使得a[0] = 10
// 第二种
b = *(p+8);				// 让p指针移动8个位置,指向a[8]的内存地址,再解引用,得到a[8]:9
open成员函数

open成员函数的作用是:将一个流对象与特定的文件关联起来,而不是生成新的流对象。
*

cout.fill()

C++ 输出流的一个成员函数。

填充字符设置是持久的 ,可能会影响后续输出。除非被再次fill而覆盖
*

动态联编
  • 定义

    联编 指的是将函数调用语句与具体的函数定义代码连接(绑定)在一起的过程。它解决的是"当程序执行到 obj->func()时,到底应该执行哪一段 func的代码?"这个问题。

  • 类别

    动态联编 :在程序运行阶段才根据对象的实际类型来确定调用哪个函数。也称为晚期绑定。

    cpp 复制代码
    #include <iostream>
    using namespace std;
    
    class Animal {
    public:
        // 关键:使用 virtual 关键字
        virtual void speak() {
            cout << "Animal speaks" << endl;
        }
    };
    
    class Dog : public Animal {
    public:
        // 重写虚函数(override关键字是C++11的好习惯,用于检查)
        void speak() override {
            cout << "Woof!" << endl;
        }
    };
    
    class Cat : public Animal {
    public:
        void speak() override {
            cout << "Meow!" << endl;
        }
    };
    
    int main() {
        Dog myDog;
        Cat myCat;
    
        Animal* animalPtr;
    
        animalPtr = &myDog;
        animalPtr->speak(); // 输出 "Woof!" - 正确!
    
        animalPtr = &myCat;
        animalPtr->speak(); // 输出 "Meow!" - 正确!
    
        return 0;
    }

    分析 :现在程序在运行时 检查 animalPtr实际指向的对象类型,并调用该类型对应的 speak方法。

    静态联编 :在程序编译链接阶段就确定了调用哪个函数。也称为早期绑定。

    cpp 复制代码
    #include <iostream>
    using namespace std;
    
    class Animal {
    public:
        void speak() {
            cout << "Animal speaks" << endl;
        }
    };
    
    class Dog : public Animal {
    public:
        void speak() { // 隐藏(不是重写)了基类的 speak
            cout << "Woof!" << endl;
        }
    };
    
    class Cat : public Animal {
    public:
        void speak() {
            cout << "Meow!" << endl;
        }
    };
    
    int main() {
        Dog myDog;
        Cat myCat;
    
        myDog.speak(); // 输出 "Woof!" - 正确
        myCat.speak(); // 输出 "Meow!" - 正确
    
        // 问题场景:使用基类指针
        Animal* animalPtr;
    
        animalPtr = &myDog;
        animalPtr->speak(); // 输出 "Animal speaks" - 不符合预期!
    
        animalPtr = &myCat;
        animalPtr->speak(); // 输出 "Animal speaks" - 不符合预期!
    
        return 0;
    }

    分析 :在编译阶段,编译器看到 animalPtr的类型是 Animal*,所以它毫不犹豫地将 speak()调用绑定到了 Animal::speak()。这就是静态联编。它不管运行时 animalPtr实际指向的是狗还是猫。

关于++ --

增1和减1运算符只能作用于左值(变量、数组元素、对象成员等),不能作用于表达式或右值。
*

深入剖析函数传参
cpp 复制代码
int swap(int &a, int &b);
int x = 10, y = 20;
swap(x+2, y+5);  // ❌ 编译错误
swap(x++, ++y);  // ❌ 编译错误
  • 第一个错误

    • x+2是一个算术表达式,计算结果是一个临时值(右值)

      解决之道:右值引用:void process(int &&a, int &&b)

    • 这个临时值没有持久的内存地址,运算完成后就被丢弃

    • swap函数的参数是 int &a(非常量左值引用)

    • 非常量左值引用不能绑定到右值

  • 第二个错误

    参数1:x++(后缀递增)

    • x++返回的是 x旧值(10)
    • 这个返回值是一个右值(临时值)
    • 同样无法绑定到非常量左值引用 int &a

    参数2:++y(前缀递增)

    • ++y返回的是 y引用(左值)
    • 理论上可以绑定到 int &b
    • 但问题在于参数求值顺序不确定
左值VS右值
  • 左值:可以出现在赋值号左边的表达式(有标识符,有内存地址)
  • 右值:只能出现在赋值号右边的表达式(临时值,没有持久内存地址)
外部类变量(extern)和外部静态类变量(static)的作用域
  • extern变量 :具有外部链接,作用域是整个程序
  • static变量 :具有内部链接,作用域仅限于当前文件
右移 >>补位规则

右移运算符(>>):补位规则取决于操作数类型

  • 无符号数:空位补0 ✅

  • 有符号数:空位补0还是补1取决于编译器实现(通常是符号位扩展)❌

    复制代码
    正数右移前: 76 (二进制: 01001100)
    正数右移后: 19 (二进制: 00010011)  // 左侧补0
    负数右移前: -100 (二进制: 10011100)  
    负数右移后: -25 (二进制: 11100111)  // 左侧补1(符号位扩展)
枚举 enum

默认第一个元素为0,其他元素被赋值就取赋值的数,没有赋值就根据前面的元素 + 1
*

ASCII

a是97,A是65
*

位运算

若是x为4,y为9,则(~x)^y的结果是( -14)。

运算过程

复制代码
  计算 ~x(按位取反)
  x:  0000 0000 0000 0000 0000 0000 0000 0100
  ~x: 1111 1111 1111 1111 1111 1111 1111 1011
  计算 (~x) ^ y(按位异或)	异或(相同为0,不同为1)
  ~x: 1111 1111 1111 1111 1111 1111 1111 1011
  y:  0000 0000 0000 0000 0000 0000 0000 1001
  	1111 1111 1111 1111 1111 1111 1111 0010
  这是补码表示的负数
  题目要十进制结果,可以转换:
  这个二进制是负数,先取反加 1 得到绝对值:
  取反:0000 0000 0000 0000 0000 0000 0000 1101
  加 1:0000 0000 0000 0000 0000 0000 0000 1110 = 14
  所以原数是 -14。
三、小结

持续更新中。。。

相关推荐
xlq223222 小时前
15.list(上)
数据结构·c++·list
云帆小二2 小时前
从开发语言出发如何选择学习考试系统
开发语言·学习
我不会插花弄玉2 小时前
排序【由浅入深-数据结构】
c语言·数据结构
光泽雨3 小时前
python学习基础
开发语言·数据库·python
Elias不吃糖3 小时前
总结我的小项目里现在用到的Redis
c++·redis·学习
ANYOLY3 小时前
Sentinel 限流算法详解
算法·sentinel
AA陈超3 小时前
使用UnrealEngine引擎,实现鼠标点击移动
c++·笔记·学习·ue5·虚幻引擎
百***06013 小时前
python爬虫——爬取全年天气数据并做可视化分析
开发语言·爬虫·python
jghhh014 小时前
基于幅度的和差测角程序
开发语言·matlab
fruge4 小时前
自制浏览器插件:实现网页内容高亮、自动整理收藏夹功能
开发语言·前端·javascript