Item 44. Casts

C++类型转换详解
I l@ve RuBoardPrevious Section Next Section

Item 44. Casts

Difficulty: 6

How well do you know C++'s casts? Using them well can greatly improve the reliability of your code.

The new-style casts in standard C++ offer more power and safety than the old-style (C-style) casts. How well do you know them? The rest of this problem uses the following classes and global variables:

class  A { public: virtual ~A(); /*...*/ }; 
A::~A() { }

class B : private virtual A  { /*...*/ };

class C : public  A          { /*...*/ };

class D : public B, public C { /*...*/ };

A a1; B b1; C c1; D d1;
const A  a2;
const A& ra1 = a1;
const A& ra2 = a2;
char c;

This Item presents four questions.

  1. Which of the following new-style casts are not equivalent to a C-style cast?

    const_cast 
    dynamic_cast
    reinterpret_cast
    static_cast
    
  2. For each of the following C-style casts, write the equivalent new-style cast. Which are incorrect if not written as a new-style cast?

    void f() 
    {
      A* pa; B* pb; C* pc;
      pa = (A*)&ra1;
      pa = (A*)&a2;
      pb = (B*)&c1;
      pc = (C*)&d1;
    }
    
  3. Critique each of the following C++ casts for style and correctness.

    void g() 
    {
      unsigned char* puc = static_cast<unsigned char*>(&c);
      signed char* psc = static_cast<signed char*>(&c);
    
      void* pv = static_cast<void*>(&b1);
      B* pb1 = static_cast<B*>(pv);
    
      B* pb2 = static_cast<B*>(&b1);
    
      A* pa1 = const_cast<A*>(&ra1);
      A* pa2 = const_cast<A*>(&ra2);
    
      B* pb3 = dynamic_cast<B*>(&c1);
    
      A* pa3 = dynamic_cast<A*>(&b1);
    
      B* pb4 = static_cast<B*>(&d1);
    
      D* pd = static_cast<D*>(pb4);
    
      pa1 = dynamic_cast<A*>(pb2);
      pa1 = dynamic_cast<A*>(pb4);
    
      C* pc1 = dynamic_cast<C*>(pb4);
      C& rc1 = dynamic_cast<C&>(*pb2);
      }
    
  4. Why is it typically unuseful to const_cast from non-const to const? Demonstrate a valid example in which it can be useful to const_cast from non-const to const.

  •  
 
I l@ve RuBoardPrevious Section Next Section
 
I l@ve RuBoardPrevious Section Next Section

Solution

graphics/bulb_icon.gif

Let's answer the questions one by one.

  1. Which of the following new-style casts are not equivalent to a C-style cast?

    Only dynamic_cast is not equivalent to a C-style cast. All other new-style casts have old-style equivalents.

    Guideline

    graphics/guideline_icon.gif

    Prefer new-style casts.


  2. For each of the following C-style casts, write the equivalent new-style cast. Which are incorrect if not written as a new-style cast?

    void f() 
    {
      A* pa; B* pb; C* pc;
      pa = (A*)&ra1;
    

    Use const_cast instead:

    pa = const_cast<A*>(&ra1); 
    
    pa = (A*)&a2;
    

    This cannot be expressed as a new-style cast. The closest candidate is const_cast, but because a2 is a const object, the results of using the pointer are undefined.

    pb = (B*)&c1; 
    

    Use reinterpret_cast instead:

      pb = reinterpret_cast<B*>(&c1); 
    
      pc = (C*)&d1;
    }
    

    The above cast is wrong in C. In C++, no cast is required:

    pc = &d1; 
    
  3. Critique each of the following C++ casts for style and correctness.

    First, a general note: All of the following dynamic_casts would be errors if the classes involved did not have virtual functions. Fortunately, A does provide a virtual function, making all the dynamic_casts legal.

    void g() 
    {
      unsigned char* puc = static_cast<unsigned char*>(&c);
      signed char* psc = static_cast<signed char*>(&c);
    

    Error: We must use reinterpret_cast for both cases. This might surprise you at first, but the reason is that char, signed char, and unsigned char are three distinct types. Even though there are implicit conversions between them, they are unrelated, so pointers to them are unrelated.

    void* pv = static_cast<void*> (&b1); 
    B* pb1 = static_cast<B*>(pv);
    

    These are both fine, but the first is unnecessary, because there is already an implicit conversion from a data pointer to a void*.

    B* pb2 = static_cast<B*> (&b1); 
    

    This is fine, but unnecessary, since the argument is already a B*.

    A* pa1 = const_cast<A*>(&ra1); 
    

    This is legal, but casting away const (or volatile) is usually indicative of poor style. Most of the cases in which you legitimately would want to remove the const-ness of a pointer or reference are related to class members and covered by the mutable keyword. See Item 43 for further discussion of const-correctness.

    Guideline

    graphics/guideline_icon.gif

    Avoid casting away const. Use mutable instead.


    A* pa2 = const_cast<A*>(&ra2); 
    

    Error: This will produce undefined behavior if the pointer is used to write on the object, because a2 really is a const object. To see why this is a legitimate problem, consider that a compiler is allowed to see that a2 is created as a const object and use that information to store it in read-only memory as an optimization. Casting away const on such an object is obviously dangerous.

    Guideline

    graphics/guideline_icon.gif

    Avoid casting away const.


    B* pb3 = dynamic_cast<B*>(&c1); 
    

    Potential error (if you try to use pb3): Because c1 IS-NOT-A B (because C is not publicly derived from B梚n fact, it is not derived from B at all), this will set pb3 to null. The only legal cast would be a reinterpret_cast, and using that is almost always evil.

    A* pa3 = dynamic_cast<A*>(&b1); 
    

    Probable error: Because b1 IS-NOT-AN A (because B is not publicly derived from A; its derivation is private), this is illegal unless g() is a friend of B.

    B* pb4 = static_cast<B*>(&d1); 
    

    This is fine, but unnecessary because derived-to-public-base pointer conversions can be done implicitly.

    D* pd = static_cast<D*>(pb4); 
    

    This is fine, which may surprise you if you expected this to require a dynamic_cast. The reason is that downcasts can be static when the target is known, but beware: You are telling the compiler that you know for a fact that what is being pointed to really is of that type. If you are wrong, then the cast cannot inform you of the problem (as could dynamic_cast, which would return a null pointer if the cast failed) and, at best, you will get spurious run-time errors and/or program crashes.

    Guideline

    graphics/guideline_icon.gif

    Avoid downcasts.


    pa1 = dynamic_cast<A*>(pb2); 
    pa1 = dynamic_cast<A*>(pb4);
    

    These two look very similar. Both attempt to use dynamic_cast to convert a B* into an A*. However, the first is an error, while the second is not.

    Here's the reason: As noted above, you cannot use dynamic_cast to cast a pointer to what really is a B object (and here pb2 points to the object b1) into an A object, because B inherits privately, not publicly, from A. However, the second cast succeeds because pb4 points to the object d1, and D does have A as an indirect public base class (through C), and dynamic_cast is able to cast across the inheritance hierarchy using the path B* D* C* A*.

    C* pc1 = dynamic_cast<C*>(pb4); 
    

    This, too, is fine for the same reason as the last: dynamic_cast can navigate the inheritance hierarchy and perform cross-casts, so this is legal and will succeed.

      C& rc1 = dynamic_cast<C&>(*pb2); 
    }
    

    Finally, an "exceptional" error: Because *pb2 isn't really a C, dynamic_cast will throw a bad_cast exception to signal failure. Why? Well, dynamic_cast can and does return null if a pointer cast fails, but since there's no such thing as a null reference, it can't return a null reference if a reference cast fails. There's no way to signal such a failure to the client code besides throwing an exception, so that's what the standard bad_cast exception class is for.

  4. Why is it normally unuseful to const_cast from non-const to const?

    The first three questions included no examples of using const_cast to add const, for example, to convert a pointer to non-const to a pointer to const. After all, explicitly adding const is usually redundant梖or example, it's already legal to assign a pointer to non-const to a pointer to const. Normally, we only need const_cast to do the reverse.

And the last part of the question: Demonstrate a valid example where it can be useful to const_cast from non-const to const.

There is at least one case in which you could usefully const_cast from non-const to const梩o call a specific overloaded function or a specific version of a template. For example:

void f( T& ); 
void f( const T& );
template<class T> void g( T& t )
{
  f( t );                       // calls f(T&)
  f( const_cast<const T&>(t) ); // calls f(const T&)
}

Of course, in the case of choosing a specific version of a template, it's usually just easier to name it explicitly instead of forcing the right deduction. For example, to call the right version of a templated function h(), writing "h<const T&>( t )" is preferable to writing "h( const_cast<const T&>(t) )".

  •  
 
I l@ve RuBoardPrevious Section Next Section
org.springframework.jdbc.BadSqlGrammarException: ### Error querying database. Cause: org.postgresql.util.PSQLException: ERROR: function func_tag_closeout_shipment_item_aggregate(unknown, unknown, text[], unknown, unknown, unknown) does not exist ヒント: No function matches the given name and argument types. You might need to add explicit type casts. 位置: 5153 ### The error may exist in file [D:\SY22BNEC31\03_PJ開発_密\0306_SourceStep3\item-tag-information-api-sana-application\bin\main\jp\co\sej\ssc\an\Sana0817MP001.xml] ### The error may involve jp.co.sej.ssc.an.SANA0817selectNormalAchievementByTrack-Inline ### The error occurred while setting parameters ### SQL: WITH t_analysis_date AS ( SELECT GENERATE_SERIES::DATE AS analysis_date FROM GENERATE_SERIES('2025-01-25'::DATE, '2025-02-01'::DATE, '1 days') ), t_shipment(shipment) AS ( VALUES ('1'),('2'),('3') -- 3便 ), v_item_tag_info(item_tag_code, employee_number) AS ( VALUES (?, ?) ), t_item_tag_daily_shipment_inf AS ( SELECT T21.item_tag_code AS item_tag_code ,T21.employee_number AS employee_number ,T21.item_code AS item_code ,T21.system_item_code AS system_item_code ,T21.original_store_code AS original_store_code ,T22.analysis_date AS analysis_date ,T23.shipment AS shipment FROM m_item_tagged T21 -- 商品タグ商品紐づけマスタ INNER JOIN m_item_tag T011 -- 商品タグマスタ ON T011.original_store_code = '123456' AND T011.item_tag_code = T21.item_tag_code AND T011.employee_number = T21.employee_number CROSS JOIN t_analysis_date T22 CROSS JOIN t_shipment T23 INNER JOIN v_item_tag_info T24 --商品タグ検索条件マスタ ON T21.item_tag_code = T24.item_tag_code AND T21.employee_number = T24.employee_number WHERE T21.original_store_code = '123456' AND T21.system_item_code IN ( '0001' ) GROUP BY T21.item_tag_code, T21.employee_number, T21.item_code, T21.system_item_code, T21.original_store_code, T22.analysis_date, T23.shipment ), t_item_tag_nodaily_shipment_inf AS ( SELECT T21.item_tag_code AS item_tag_code ,T21.employee_number AS employee_number ,T21.item_code AS item_code ,T21.system_item_code AS system_item_code ,T21.original_store_code AS original_store_code ,T22.analysis_date AS analysis_date FROM m_item_tagged T21 -- 商品タグ商品紐づけマスタ INNER JOIN m_item_tag T011 -- 商品タグマスタ ON T011.original_store_code = '123456' AND T011.item_tag_code = T21.item_tag_code AND T011.employee_number = T21.employee_number CROSS JOIN t_analysis_date T22 INNER JOIN v_item_tag_info T23 --商品タグ検索条件マスタ ON T21.item_tag_code = T23.item_tag_code AND T21.employee_number = T23.employee_number WHERE T21.original_store_code = '123456' AND T21.system_item_code IN ( '' ) GROUP BY T21.item_tag_code, T21.employee_number, T21.item_code, T21.system_item_code, T21.original_store_code, T22.analysis_date ), daily_nodaily_result AS ( SELECT -- デイリー品の実績取得 T01.item_tag_code AS item_tag_code ,T01.employee_number AS employee_number ,T01.analysis_date AS analysis_date ,T01.shipment AS shipment ,COALESCE(SUM(T02.delivery_quantity), 0) AS delivery_quantity ,COALESCE(SUM(T02.delivery_amount), 0) AS delivery_amount ,COALESCE(SUM(T02.sales_quantity), 0) AS sales_quantity ,COALESCE(SUM(T02.sales_amount), 0) AS sales_amount ,COALESCE(SUM(T02.gross_amount), 0) AS gross_amount ,COALESCE(SUM(T02.disposal_quantity), 0) AS disposal_quantity ,COALESCE(SUM(T02.disposal_amount), 0) AS disposal_amount ,0 AS ethical_sales_quantity ,0 AS ethical_sales_amount ,COALESCE(SUM(T05.closeout_sales_quantity), 0) AS forsake_sales_quantity ,COALESCE(SUM(T05.closeout_sales_amount), 0) AS forsake_sales_amount FROM t_item_tag_daily_shipment_inf T01 LEFT JOIN -- 便別単品集計 func_shipment_item_aggregate ('123456', NULL, ARRAY [ '0001' ] , '2025-01-25', '2025-02-01', '2024-01-16') T02 ON T02.system_item_code = T01.system_item_code AND T02.shipment = T01.shipment AND T02.analysis_date = T01.analysis_date LEFT JOIN -- 見切り便別単品集計 func_tag_closeout_shipment_item_aggregate ('123456', NULL, ARRAY [ '0001' ] , '2025-01-25', '2025-02-01', '2024-01-16') T05 ON T05.system_item_code = T01.system_item_code AND T05.shipment = T01.shipment AND T05.analysis_date = T01.analysis_date GROUP BY T01.item_tag_code, T01.employee_number, T01.analysis_date, T01.shipment UNION ALL SELECT -- 非デイリー品の実績取得 T01.item_tag_code AS item_tag_code ,T01.employee_number AS employee_number ,T01.analysis_date AS analysis_date ,'1' AS shipment ,COALESCE(SUM(T02.delivery_quantity), 0) AS delivery_quantity ,COALESCE(SUM(T02.delivery_amount), 0) AS delivery_amount ,COALESCE(SUM(T02.sales_quantity), 0) AS sales_quantity ,COALESCE(SUM(T02.sales_amount), 0) AS sales_amount ,COALESCE(SUM(T02.gross_amount), 0) AS gross_amount ,COALESCE(SUM(T02.disposal_quantity), 0) AS disposal_quantity ,COALESCE(SUM(T02.disposal_amount), 0) AS disposal_amount ,0 AS ethical_sales_quantity ,0 AS ethical_sales_amount ,COALESCE(SUM(T05.closeout_sales_quantity), 0) AS forsake_sales_quantity ,COALESCE(SUM(T05.closeout_sales_amount), 0) AS forsake_sales_amount FROM t_item_tag_nodaily_shipment_inf T01 LEFT JOIN -- 日別単品集計 func_daily_item_aggregate ('123456', NULL, ARRAY [ '' ] , '2025-01-25', '2025-02-01', '2024-01-16') T02 ON T02.system_item_code = T01.system_item_code AND T02.analysis_date = T01.analysis_date LEFT JOIN -- 見切り日別単品集計 func_tag_closeout_daily_item_aggregate ('123456', NULL, ARRAY [ '' ] , '2025-01-25', '2025-02-01', '2024-01-16') T05 ON T05.system_item_code = T01.system_item_code AND T05.analysis_date = T01.analysis_date GROUP BY T01.item_tag_code, T01.employee_number, T01.analysis_date ) SELECT T06.item_tag_code ,T06.employee_number ,T06.analysis_date ,T06.shipment ,COALESCE(SUM(T06.delivery_quantity), 0) AS delivery_quantity ,COALESCE(SUM(T06.delivery_amount), 0) AS delivery_amount ,COALESCE(SUM(T06.sales_quantity), 0) AS sales_quantity ,COALESCE(SUM(T06.sales_amount), 0) AS sales_amount ,COALESCE(SUM(T06.gross_amount), 0) AS gross_amount ,COALESCE(SUM(T06.disposal_quantity), 0) AS disposal_quantity ,COALESCE(SUM(T06.disposal_amount), 0) AS disposal_amount ,0 AS ethical_sales_quantity ,0 AS ethical_sales_amount ,COALESCE(SUM(T06.forsake_sales_quantity), 0) AS forsake_sales_quantity ,COALESCE(SUM(T06.forsake_sales_amount), 0) AS forsake_sales_amount FROM daily_nodaily_result T06 GROUP BY T06.item_tag_code ,T06.employee_number ,T06.analysis_date ,T06.shipment ORDER BY T06.item_tag_code ,T06.employee_number ,T06.analysis_date ,T06.shipment ### Cause: org.postgresql.util.PSQLException: ERROR: function func_tag...
10-17
【电动汽车充电站有序充电调度的分散式优化】基于蒙特卡诺和拉格朗日的电动汽车优化调度(分时电价调度)(Matlab代码实现)内容概要:本文介绍了基于蒙特卡洛和拉格朗日方法的电动汽车充电站有序充电调度优化方案,重点在于采用分散式优化策略应对分时电价机制下的充电需求管理。通过构建数学模型,结合不确定性因素如用户充电行为和电网负荷波动,利用蒙特卡洛模拟生成大量场景,并运用拉格朗日松弛法对复杂问题进行分解求解,从而实现全局最优或近似最优的充电调度计划。该方法有效降低了电网峰值负荷压力,提升了充电站运营效率与经济效益,同时兼顾用户充电便利性。 适合人群:具备一定电力系统、优化算法和Matlab编程基础的高校研究生、科研人员及从事智能电网、电动汽车相关领域的工程技术人员。 使用场景及目标:①应用于电动汽车充电站的日常运营管理,优化充电负荷分布;②服务于城市智能交通系统规划,提升电网与交通系统的协同水平;③作为学术研究案例,用于验证分散式优化算法在复杂能源系统中的有效性。 阅读建议:建议读者结合Matlab代码实现部分,深入理解蒙特卡洛模拟与拉格朗日松弛法的具体实施步骤,重点关注场景生成、约束处理与迭代收敛过程,以便在实际项目中灵活应用与改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值