第十二章 类和动态内存转换

c++自动提供下一继承成员函数:

● 默认构造函数,如果没有定义构造函数。

● 默认析构函数

● 复制构造函数

● 赋值运算符

● 地址运算符

默认构造函数

如果没有提供任何构造函数,将创建默认构造函数。

例如:

Klunk::Klunk() {}

实际上编译器生成一个不接收任何参数,也不执行任何操作的构造函数,c++创建对象总是会调用一个构造函数的。

如果定义了某个构造函数,将不会定义默认构造函数,如果要使用默认构造函数,必须重写一个默认构造函数。

带参数的构造函数也可能是默认构造函数,例如以下情况:

Klunk::Klunk(m = 1, n = 2)  {
    ...
}

Klunk::Klunk(m = 1)  {
    ...
}
所有参数都有默认值的话,也属于默认构造函数,为了避免二义性,默认构造函数只能有一个
//使用默认构造函数的几种方式。
Klunk lunk;
Klunk lunk = lunk();
Klunk *lunk = new lunk();

复制构造函数

复制构造函数用于将一个对象复制到新创建的对象中;就是说用于初始化过程,而不是赋值过程。

原型: class_name(const Class_name &);

MyString(const MyString &);

何时调用复制构造函数

1 新建对象,并初始化为已有的对象。

MyString str1;  //调用默认构造函数

MyString myStr(str1); //使用复制构造函数

MyString myStr = str1; //使用复制构造函数

MyString *myStr = new MyString(str1); //使用复制构造函数

当函数安置传递对象,或函数返回对象时,都将使用复制构造函数。

所以按值传递对象会增加存储空间以及调用构造函数的时间开销

默认的复制构造函数

默认的复制构造函数逐个复制非静态成员(成员复制又叫浅复制),复制的是成员的值。

MyString myStr = str1;将str1的成员变量逐个复制给myStr,如果成员有指针,只会复制指针的值。

所以如果成员变量是一个指针的话,需要深拷贝指针所指向的内容。如果只是复制指针的值的话,两个对象的指针将指向同一快内存,当其中一个对象delete的时候,另一个在delete将出现重复删除,引起crash。

可以像下边一样重写一个复制构造函数,创建一块内存,来存储。

MyString::MyString(const MyString & st) {
    len = st.len;
    str = new char[len +1];
    std::strcpy(str, st.str);
}

赋值运算符

赋值运算符的使用场景是:将已有的对象赋值给另外一个对象,这是后调用赋值运算符,注意和复制构造函数的区别,复制构造函数是用在创建对象的初始化阶段。

例如:

MyString string1;

string1 = string2;//string2是已有的对象。

赋值运算符是通过自动重载赋值运算符实现的。

原型:Class_name & Class_name::operator=(const Class_name &); 参数和返回值是一个类对象引用

赋值运算符和复制构造函数一样,都是浅拷贝。如果有指针存在,需要重写。

使用指向对象的指针

MyString *myStr = new MyString(str1); 

使用new 来创建对象,并用myStr指向此对象,此对象将存储在堆内存中,当对象使用完之后,必须用delete删除对象。

何时调用析构函数:

        1 如果对象是动态变量,则当执行完定义该对象的程序块时,将调用对象的析构函数。

        2 如果对象时静态变量(外部全局变量、静态对象),则程序结束时候调用析构函数。

        3 如果时new创建的,当调用delete时候,调用析构函数。

对于构造函数使用new的类,应该注意以下几点:

        1 对于指向的内存时由new分配的所有类成员,有应在类的析构函数中对其使用delete,delete将释放分配的内存

        2 如果析构函数通过对指针类成员使用delete来释放内存,则每个构造函数都应该使用new来初始化指针,或设置为空指针。

        3 构造函数中要么使用new,要么使用new[],不能混用,因为析构函数只有一个,new[]对应delete[];

        4 应定义一个重载复制运算符的类成员函数,如下所示

c_name & c_name::operator=(const c_name & cn) {
    if (this == &cn) {
        retunr *this;
    }
    delete[] c_pointor;
    c_pointor = new typr_name[size];
    return *this;
}

例子:

#ifndef __MY_STRING_H__
#define __MY_STRING_H__

void start_slt_eng();
class MyString {
    private:
        char * _str;
        int _len;
        static int _num_string;
    public:
        MyString();
        MyString(const char * str);
        MyString(const MyString & str);
        friend std::ostream & operator<<(std::ostream & os, const MyString & str);
        const MyString & operator=( const MyString & str);
        ~MyString();
};

#endif //__MY_STRING_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include "my_string.h"

using namespace std;

void start_my_string_text() {
    MyString str = MyString();
    MyString str1("textmy string");
    MyString *str2 = new MyString("textmy p string");
    cout << str1 << endl;
    cout << str2 << endl;
    cout << *str2 << endl;
    MyString str3(str1);
    delete str2;
    MyString str4;
    str4 = str1;
    cout << "fuzhi" << str4;
}

MyString::MyString() {
    _str = new char[12];
    memcpy(_str , {"Default str"}, 12);
    _len = strlen(_str);
    cout << "Default constructor: " << _str<< endl;
}

MyString::MyString(const char * str) {
    _len = strlen(str);
    _str = new char[_len];
    memcpy(_str, str, _len);
    cout << "constructor: " << _str<< endl;
}

MyString::MyString(const MyString & str) {
    _len = str._len;
    _str = new char[_len];
    memcpy(_str, str._str, _len);
    cout << "Copy constructor: " << _str<< endl;
}

ostream & operator<<(ostream & os, const MyString & str) {
    os << str._str << endl;
    return os;
}

const MyString & MyString::operator=( const MyString & str) {
    _len = str._len;
    _str = new char[_len];
    memcpy(_str, str._str, _len);
    cout << "= constructor: " << _str << endl;
    return *this;
}

MyString::~MyString() {
    cout << "delete: " << _str << endl;
    delete [] _str;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值