proof1 发表于 2024-10-18 09:02

求助: RECT 结构,赋值语法

VS2005、2008、2013    C++语言   DirectX 9.0

---------------------------------------------------------
RECT 结构原型:
typedef struct _RECT {
    LONGleft;
    LONGtop;
    LONGright;
    LONGbottom;
} RECT, *PRECT;


设置RECT变量的三种方法:
1、初始化方式
RECTr = { 0, 0, 6, 8 };


2、单个赋值
RECTr ;
r.left = 15;
r.top = 16;
r.right = 300;
r.bottom = 400;


3、调用SetRect函数
RECTr ;
SetRect( &r , 0 , 0 , 123 , 600 );
---------------------------------------------------------
  问题: r 需频繁换值,想用如下方式赋值:
RECTr ;
r = { 0 , 0 , 6 , 8 };            // 报错
……
r = { 5 ,6 , 400 , 600 };      // 报错


如何实现类似 r = {12, 20, 56, 108} 这种简便赋值功能?
有说用重构=运算符,有说用宏定义的。能否给出完整代码?


proof1 发表于 2024-10-18 09:22

本帖最后由 proof1 于 2024-10-18 09:23 编辑

用这种方式行吗,重复声明:
RECTr = { 0, 0, 6, 8 };
……
RECTr = { 15, 16, 300, 400 };
……
RECTr = { 12, 20, 56, 108 };
……

编译可以通过,速度是否比 SetRect() 函数慢?

dccif 发表于 2024-10-18 12:04

在C++中直接使用 {} 初始化方式进行赋值时,只能用于变量声明时。对于像 RECT 这样的结构体,在已经声明过的变量上使用 {} 赋值会导致语法错误。要实现简便的赋值方式,确实可以通过重载 = 运算符或者宏定义来实现。

解决方案 1:重载赋值运算符

通过为 RECT 结构体重载赋值运算符,我们可以实现类似 {} 语法的赋值功能。由于 RECT 是 Windows API 中的一个标准结构体,不能直接修改其定义,因此我们可以创建一个包装类来实现这一功能。

#include <windows.h>
#include <iostream>

// 包装类
class MyRect {
public:
    RECT rect;

    // 默认构造函数
    MyRect() {
      SetRect(&rect, 0, 0, 0, 0);
    }

    // 参数化构造函数
    MyRect(LONG left, LONG top, LONG right, LONG bottom) {
      SetRect(&rect, left, top, right, bottom);
    }

    // 重载赋值运算符
    MyRect& operator=(const MyRect& other) {
      rect = other.rect;
      return *this;
    }

    // 重载赋值运算符,接受初始化列表
    MyRect& operator=(std::initializer_list<LONG> list) {
      if (list.size() == 4) {
            auto it = list.begin();
            rect.left = *it++;
            rect.top = *it++;
            rect.right = *it++;
            rect.bottom = *it;
      }
      return *this;
    }
};

int main() {
    MyRect r;

    // 通过赋值运算符来赋值
    r = {0, 0, 6, 8};
    std::cout << "r: " << r.rect.left << ", " << r.rect.top << ", "
            << r.rect.right << ", " << r.rect.bottom << std::endl;

    r = {5, 6, 400, 600};
    std::cout << "r: " << r.rect.left << ", " << r.rect.top << ", "
            << r.rect.right << ", " << r.rect.bottom << std::endl;

    return 0;
}

解决方案 2:使用宏定义

宏定义也是一种简便的方法,但其灵活性和安全性不如重载运算符。使用宏定义的方法可以避免修改代码结构,适合在不希望修改现有结构体定义时使用。

#include <windows.h>
#include <iostream>

#define SET_RECT(r, l, t, ri, b) (r.left = (l), r.top = (t), r.right = (ri), r.bottom = (b))

int main() {
    RECT r;

    // 使用宏定义来赋值
    SET_RECT(r, 0, 0, 6, 8);
    std::cout << "r: " << r.left << ", " << r.top << ", "
            << r.right << ", " << r.bottom << std::endl;

    SET_RECT(r, 5, 6, 400, 600);
    std::cout << "r: " << r.left << ", " << r.top << ", "
            << r.right << ", " << r.bottom << std::endl;

    return 0;
}

总结

重载运算符 的方式更加灵活和现代化,适用于需要更好可维护性和扩展性的代码。

宏定义 则更加直接,适合不想进行较大代码改动的场景。


你可以根据具体需求选择最适合的方案。

神奇的ai

—— 来自 鹅球 v3.2.91

CyanCloverFern 发表于 2024-10-18 13:00

本帖最后由 CyanCloverFern 于 2024-10-18 13:07 编辑

VS2005、2008、2013    C++语言   DirectX 9.0

应该是开发工具太老了,{}赋值以及更宽松的初始化规则需要到17还是20吧,一个pod类型的结构没有道理不能使用 = {a, b, c, d}的形式

而且二楼,你想钻空子,不应该用 r = Rect {a, b, c, d} 的方式来钻吗?重定义变量把作用域搞的一团糟,除了msvc,如果遇到goto+label的组合也跨不过去(用在状态机以及消息处理函数里)。






tsubasa9 发表于 2024-10-18 13:39

咋还有人回这人,他把泥潭当百度知道用呢

精钢魔像 发表于 2024-10-18 14:15

楼主可能不是人类,会用网络问人却不会用网络搜索

5long 发表于 2024-10-18 14:16

老老实实用 SetRect,增加代码 grepability

mimighost 发表于 2024-10-18 15:20

#include <windows.h>

// 使用宏定义
#define RECT_INITIALIZER(left, top, right, bottom) { (left), (top), (right), (bottom) }

#define SET_RECT(rect, left, top, right, bottom) \
    do { \
      (rect).left = (left); \
      (rect).top = (top); \
      (rect).right = (right); \
      (rect).bottom = (bottom); \
    } while(0)

// 使用运算符重载
struct RECT_WRAPPER : public RECT {
    RECT_WRAPPER& operator=(const RECT& other) {
      left = other.left;
      top = other.top;
      right = other.right;
      bottom = other.bottom;
      return *this;
    }

    RECT_WRAPPER& operator=(const LONG (&arr)) {
      left = arr;
      top = arr;
      right = arr;
      bottom = arr;
      return *this;
    }
};

int main() {
    // 使用宏定义
    RECT r1 = RECT_INITIALIZER(0, 0, 6, 8);
    SET_RECT(r1, 5, 6, 400, 600);

    // 使用运算符重载
    RECT_WRAPPER r2 = { 0, 0, 6, 8 };
    r2 = { 5, 6, 400, 600 };

    return 0;
}


claude给你的答案

proof1 发表于 2024-10-19 18:49

感谢!
页: [1]
查看完整版本: 求助: RECT 结构,赋值语法