C++常见问题

本文介绍了C++中的一些常见问题,包括四种类型转换的区别,类大小计算规则,字符指针类型,成员函数指针的使用,虚函数表的原理,深拷贝与浅拷贝的差异,以及字节对齐和static修饰符的作用。对于const修饰的成员函数调用非const成员函数的情况也进行了说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.reinterpret_cast,static_cast,dynamic_cast、const_cast区别

  • reinterpret_cast,非常随意的一种类型转换方式,不做任何检查,非常危险,跟C的强制类型转换差不多
  • static_cast,同C的隐示类型转换差不多,用做下行转换时不提供动态类型检查
  • dynamic_cast,类层次上的转换,下行转换时提供动态类型检查,需要有虚函数表,转换失败返回nullptr
  • const_cast,可以去掉类型的const与volatile属性

2.类的大小

  • 空类,实例在内存中得有地址,编译器添1个字节
class CTest1
{
};
int size = sizeof(CTest1); // 1
  • 普通类,计算大小时不算静态成员变量,只计算普通成员大小+虚表指针大小
class CTest2
{
public:
    virtual void func() {}
    static void func2() {}
protected:
    static int c;
private:
    int a;
    char* p;
};

int size = sizeof(CTest2); // 12
  • 普通派生类,大小为基类大小+自己大小
class CTest3 : public CTest2
{
private:
    int c;
};

int size = sizeof(CTest3); // 16
  • 虚继承的派生类,大小为基类大小+自己大小+虚基类表指针
class CTest4 : public CTest2
{
private:
    int c;
};

int size = sizeof(CTest4); // 20

3.char指针

  • char*  字符指针;字符串指针
  • char**  指向char*的指针
  • char a[]  字符数组,a表示数组首地址 char*
  • char *a[]  char*数组,a表示数组首地址 char**
char s[] = "test";
s[0] = 'a';            // ok
char* p = s;
p[0] = 'a';            // ok
p = "test";
p[0] = 'a';            // error
s = p;                 // error

char* a[] = {"test1", "test2"};
int size = sizeof(a);  // 8
char** p1 = a;         // ok

4.成员函数指针

  • static函数不需要限定符CTest::
  • 成员函数需要限定符CTest::,注意不是实例test::
class CTest
{
public:
    virtual void func() { cout << "func" << endl; }
    void func2() { cout << "func2" << endl; }
    static void func3() { cout << "func3" << endl; }
};
    typedef void(*Func)(void);
    typedef void(CTest::*Func2)(void);

    CTest test;
    Func f = &CTest::func3;
    f();                        // func3
    Func2 f2 = &CTest::func2;
    (test.*f2)();               // func2
    f2 = &CTest::func;
    (test.*f2)();               // func

5.虚函数表

  • 有虚函数的类都有虚函数表,类对象都有虚函数指针
  • 多重继承情况下,有虚函数的基类都有虚函数表,所以派生类有多个虚函数表,派生类的虚函数声明放在第一个虚函数表中
  • 虚函数表指针位于实例最前面
  • 编译时确定虚函数表,构造对象时初始化虚函数表成员
  • 通过虚函数表可以访问到private的virtual函数
class CTest5
{
private:
    virtual void test() { cout << "test" << endl; }
};

    typedef void(*Func)(void);
    CTest5 test;
    Func f = (Func)*((int*)(*(int*)(&test)) + 0);
    f();            // test

class CBase
{
public:
    virtual void test() { cout << "base test" << endl; }
};

class CDriver: public CBase
{
private:
    virtual void test() { cout << "driver test" << endl; }
};
    
    CBase *pb = new CDriver;
    pb->test();     // driver test

    CDriver *pd = dynamic_cast<CDriver *>(pb);
    pd->test();     // error

6.深拷贝与浅拷贝

  • 在成员变量包含指针时,需要注意浅拷贝会导致2个对象的指针指向同一片内存,释放时恨容易造成同一内存两次释放
class CTest6
{
public:
    CTest6() { n = 10; p = new int(0); }
    ~CTest6() { delete p; }
    CTest6(const CTest6& test) { p = new int; *p = *test.p; }
private:
    int n;
    int* p;
};

7.字节对齐

  • 结构体每个成员的起始位置都应为自身大小的整数倍
  • 结构体大小必须是结构体内最大成员的整数倍,不足则补齐

某些时候需要禁用字节对齐,如通信帧定义    #pragma pack(1)

struct MyStruct
{
    int a;        // offset 0-3 补4字节
    double b;     // offset 8-15
    char c;       // offset 16  补7字节
};

int size = sizeof(MyStruct);    // 24

8.static修饰符

  • 全局变量   限定作用域到声明此变量的编译单元
  • 普通变量   此局部变量存储于静态存储区,更改了生命周期,不更改作用域
  • 普通函数   同全局变量
  • 成员变量   成员归属升级为类  除static const int外都需要在类定义体外定义
  • 成员函数   同成员变量 static成员函数不能声明为const,const修饰的表明函数不会修改对象,static成员函数不属于对象
class CTest6
{
public:
    CTest6() { n = 10; p = new int(0); }
    ~CTest6() { delete p; }
    CTest6(const CTest6& test) { p = new int; *p = *test.p; }
    static const int a = 1;
    static const float f;
private:
    int n;
    int* p;
};

const float CTest6::f = 0.5f;

9.const修饰的成员函数调用非const成员函数

class CTest6
{
public:
    CTest6() { n = 10; p = new int(0); }
    ~CTest6() { delete p; }
    CTest6(const CTest6& test) { p = new int; *p = *test.p; }
    static const int a = 1;
    static const float f;
    void test1()const { CTest6* p = const_cast<CTest6*>(this);  p->test2(); }
    void test2(){ cout << "test2" << endl; }
private:
    int n;
    int* p;
};

    const float CTest6::f = 0.5f;

    CTest6 test;
    test.test1();   // test2

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值