C++: 16.03.04实验课总结

C++: 16.03.04实验课总结

标签: C++ 实验课

by 小威威


1.缺省构造函数

缺省构造函数主要有两种类型:(1)无形参;(2)有形参。

class Student {
    public:
        Student();  // 无形参
        Student(int a1, int b1 = 0, int c1 = 0);  // 有形参
    private:
        int a;
        int b;
        int c;
};

当定义对象时,如:

Student st; // valid
Student st(); // invalid

还有另外一种定义方式:

Student st = Student();  // valid

虽然构造函数括号里没有参数,但是定义对象时不能加上空括号,这时构造函数特殊的地方。如果加上括号,编译器会识别成Student() st,错误信息显示没有Student()这个类。

第二种定义对象的方式类似于一般的函数调用。

但是缺省的参数是有规定的。如上面的构造函数,只能有两种缺省类型:

Student (int a1, int b1 = 0, int c1 = 0);  \\ valid
Student (int a1, int b1, int c1 = 0); \\ valid
Student (int a1 = 0, int b1 = 0, int c1 = 0); \\ invalid
Student (int a1 = 0, int b1 = 0, int c1);  \\ invalid
Student (int a1 = 0, int b1, int c1 = 0);  \\ invalid
Student (int a1 = 0, int b1, int c1);  \\ invalid

即第一个参数不能缺参,不能间隔缺参,不能所有参数都缺省。第一,编译器无法识别你输入的形参是哪一个,第二,对于全部参数缺省,会导致调用函数产生歧义。因为你将三个参数都缺省,这就与没有参数的Student()重复。一旦调用无参数,编译器不知道是调用哪个构造函数。

因此,如果要三个参数都缺参,必须删去Student(),即是:

class Student {
    public:
        Student(int a1, int b1 = 0, int c1 = 0); // 无需定义Student()
    private:
        int a;
        int b;
        int c;
};

2.谷歌风格问题

(1)构造函数只有一个参数的时候,要在其声明的语句前加上explicit。不加也不会编译出错,只是不符合谷歌风格。

explicit Student(int a1);

(2)strcpy不符合谷歌风格,应使用strncpy或者snprintf。这里我要着重介绍一下snprintf的用法。

snprintf(str, size_max_str, key);

snprintf位于的头文件中,是C函数库里的函数。
第一个参数是目标字符串,也就是我们要复制过去的位置。
第二个参数是第一个参数也就是目标字符串的最大字节。
第三个参数就是我们要拷贝的内容。

snprintf很特别,编译器会得到key的字节数然后跟第二个参数比较。
如果key的字节数小于第二个参数,那么就直接把key的内容复制到str中并加上’\0’。
如果key的字节数大于等于第二个参数,那么就将key中的前(size_max_str - 1)字符复制到str中,并加上’\0’。这点是要值得注意的。

3.浅复制与深复制

浅复制通俗来讲就是系统定义的复制构造函数,即不会出现在我们的代码中。

深复制通俗来讲就是我们自己定义的复制构造函数,即会出现在我们的代码中。

当一个类没有指针成员,我们一般可以直接忽略复制构造函数,但是一旦有指针成员,就要注意了,浅复制可能会导致意想不到的后果。浅复制指针对象,只是将一个指针直接赋值给另外一个指针,即两个指针的内容是一样的,也就是说两个指针指向同一块内存。一旦析构函数中有delete语句,可能会导致内存二次释放,引发意想不到的后果。但是,对于深复制,是将指针指向的内容进行复制,使得两个指针不指向同一块内存而分别指向两块内容相同的内存。这样就不会因为delete而导致二次释放内存。更详细地来讲旧时我们在复制构造函数中用new语句在堆中重新分配一块内容来存储指针指向的对象,然后将内存的地址返回给复制的指针。

浅复制与深复制是一个很重要的问题,值得我们注意!

4.数字与字符串的转换

在这里我要介绍两种方法:第一,用snprintf函数;第二,通过stringstream进行转换。

先上代码:

# include <iostream>
# include <cstdio>
# include <string>
# include <sstream>

using namespace std;

int main(void) {
    char str1[100];
    char str2[100];
    char str3[100];
    int j = snprintf(str1, sizeof(str1), "Hello~"); \\ 复制
    cout << "j: " << j << "  " << "str1: " << str1 << endl;
    j = snprintf(str2, sizeof(str2), "The word I want to say: %s", "Hello");  \\ 格式化
    cout << "j: " << j << "  " << "str2: " << str2 << endl;
    j = snprintf(str3, sizeof(str3), "%d", 111);   \\ 格式化(转化)
    cout << "j: " << j << "  " << "str3: " << str3 << endl;
    stringstream st, st1;
    st << 111;
    string str4;
    st >> str4;
    cout << "str4: " << str4 << endl;
    st1 << 121;
    const char* str5;
    str5 = st1.str().c_str();
// st1.str()将str1中的内容转化为string类型。str1.str().c_str()将string转化成cstring 
    cout << "str5: " << str5 << endl;
    return 0;
}

在上文我有提到,snprintf可代替strcpy函数。接下来我将要讲解snprintf的第二个用法:就是字符串的格式化。

snprintf函数的格式如下:
int snprintf ( char * s, size_t n, const char * format, content );

用snprintf可以将数字转化成字符串类型,但是snprintf函数有个缺陷就是收到目标字符串的大小的影响。一旦要格式化的字符串大于目标字符串所占字节数,将会导致字符串的复制不完整!

因此,这种转化用stringstream对象来实现较好。
stringstream类是定义于<sstream>的头文件内,它通过”<<” 与”>>”来实现内容的流入与流出。其实,stringstream对象就想中介,他存储着你输入的内容,然后输出到你想要转化的类型的对象中去,既不用考虑大小,代码写起来也比较简单。

但要注意的是:一个stringstream对象只能做一次中介。倘若要转换新的字符串,那么要定义一个新的stringstream对象。stringstream::clear函数是进行缓冲区重置,并不是清空缓冲区。如stringstream对象st:

st << 111;
st << 121;

st的输出结果仍是111
st << 111;
st.clear();
st << 121;

那么st的输出结果便是111121

4.返回对象与返回引用的区别

首先我们先来说明一下复制构造函数的执行条件:
(1)对象赋值操作。

// 假设有一个类为Box。
Box box1, box2;
box2 = box1;   // 对象赋值操作

(2)函数调用。

// 假设有一个类为BoxBox box1;
Box box2(box1);// 函数调用,传入对象作为参数

(3)对象作为函数返回值。(复制一个临时对象返回到调用函数处)

Box Change {
    Box x1;
    return x1;  // 对象作为函数返回值
}

返回对象会执行复制构造函数,返回引用不会执行复制构造函数。

检验的方法很简单,在类的析构函数里输出内容,然后根据输出语句的数量就能作出判断。


以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值