c++构造函数的显式和隐式调用

如果在编写类时没有显示的写出其构造函数,析构函数,以及重载赋值操作符,编译器会在编译代码时,会为该类加上这些。

其形式大致如下:

A(){}

A& operator =(const A& a)
{
    // 这个地方可能有点不当,只是为了表明这是一个浅拷贝
    memcpy(this, &a, sizeof(A));
    return *this;
}

A(const A& a)
{
   // 这儿调用了赋值重载函数
   *this = a;
}

 // 注意在析构函数前不会加上virtual关键字
 ~A(){}

下面给出一些示例,注释部分说明了函数调用的情况:

void f()
{
   // A()构造函数被调用
   A a;
   // A(const A& a)构造函数被调用
   A b(a);
   // A(const A& a)构造函数被调用
   A c = a;
   // A& operator = (const A& a)赋值操作符重载函数被调用
   b = c;
}
// 离开f()函数之前,a,b,c的析构函数被调用,做一些清理工作

“A c = a;”

这句代码实际调用的是拷贝构造函数,而非赋值函数。

因此,我们可以构造出这样的代码。

class A
{
 private:
    int *m_data;
    std::string ss;
 public:
    A()
    {
        m_data = NULL;
    }
    A(int n)
    {
        m_data = NULL;
        if (n>0)
            m_data = new int[n];
    }
    A& operator =(const A& a)
    {
        memcpy(this, &a, sizeof(A));
        return *this;
    }
    virtual ~A()
    {
        if (NULL!=m_data)
        {
            delete [] m_data;
            m_data = NULL;
        }
    }
};


 int main(int argc, char* argv[])
{
    // 将整数3赋值给一个对象
     A a = 3;    
    return 0;
}

将整数3赋值给一个A类型对象a,然而以上代码可以编译通过。 -- 有点不合常理

这是由于“单参数构造函数”被自动类型转换(这是一个隐式转换)。

可以通过explicit关键字 ,阻止“以赋值语法进行带有转型操作的初始化”。如下所示:

class A
{
 private:
    int *m_data;
    std::string ss;
 public:
    A()
    {
        m_data = NULL;
    }
    explicit A(int n)
    {
        m_data = NULL;
        if (n>0)
            m_data = new int[n];
    }
    A& operator =(const A& a)
    {
        memcpy(this, &a, sizeof(A));
        return *this;
    }
    virtual ~A()
    {
        if (NULL!=m_data)
        {
            delete [] m_data;
            m_data = NULL;
        }
    }
};


 int main(int argc, char* argv[])
{
    // A a = 3; // 编译无法通过
     A b(3);     // 可以编译通过
    
    return 0;
}

 

### C++调用构造函数的方法 在C++中,调用构造函数是一种常见的需求,尤其是在处理继承关系或者防止的类型转换时。以下是关于如何调用构造函数的具体方法及其语法。 #### 1. 使用括号法调用构造函数 当定义一个对象并希望立即对其进行初始化时,可以使用括号法来调用构造函数[^1]。例如: ```cpp class MyClass { public: MyClass(int value) : m_value(value) {} private: int m_value; }; MyClass obj(42); // 调用带有int数的构造函数 ``` 此方适用于任何具有适当数列表的构造函数。 #### 2. 防止类型转换通过`explicit`关键字 为了防止单构造函数被用来进行类型转换,可以在定义构造函数时使用`explicit`关键字[^2]。这使得只有通过调用才能触发此类构造函数的行为。例如: ```cpp class MyClass { public: explicit MyClass(int value) : m_value(value) {} private: int m_value; }; // 下面这种转换将不再有效 double d = MyClass(42); // 而必须这样调用 MyClass obj(42); ``` 这种方增强了程序的安全性可读性。 #### 3. 编译器自动生成的构造函数 如果没有为类提供任何构造函数,则编译器会生成默认构造函数、拷贝构造函数析构函数等成员函数[^3]。然而,在某些特定场景下(比如涉及多态行为),可能需要手动声明这些特殊成员函数以满足设计需求。 #### 4. 子类中调用父类构造函数 在一个派生类中,可以通过在其构造函数初始值列中指明要调用哪个基类构造函数[^4][^5]。这是因为在创建派生类实例之前,必须先完成对其基础部分即基类实例化的准备工作。示例如下: ```cpp class Base { public: Base(const std::string& name):m_name(name){} protected: std::string m_name; }; class Derived : public Base{ public: Derived(const std::string& name, int id) :Base(name), m_id(id){} // 调用了基类Base的构造函数 private: int m_id; }; ``` 上述代码展示了如何在派生类`Derived`的构造函数调用基类`Base`的一个接受字符串作为唯一数的构造函数。 --- ### 总结 以上就是在C++编程语言中的几种主要调用构造函数的方及相关注意事项。每种情况都有其适用范围与局限性,合理运用能够提升代码质量与执行效率。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值