C++面向对象高级编程笔记02--GeekBand

来源:互联网 发布:网络药店排名 编辑:程序博客网 时间:2024/06/04 18:43

第二个周 01

这节课主要讲了Big Three(拷贝构造,拷贝赋值,析构函数)。

为什么需要这几个特殊函数?这个周要讲的是 class with pointer,在类中成员要使用指针,多半要动态分配内存,考虑下面几种对象的创建和赋值场景

String str1("Hello");

String str2(str1);

String str3 = str1;

String str4 = new String("Hello");

str2和str3,如果不使用拷贝构造和拷贝赋值,则会使用编译器默认的拷贝和赋值,bit by bit的拷贝。最终的结果是浅拷贝,而我们通常要的是深拷贝。

以String为例,

class String {
public:
String(const char* cstr = 0);
String(const String& str); //拷贝构造
String& operator=(const String& str); //拷贝赋值
~String(); //析构函数
char* get_c_str() const { return m_data; }
private:
char* m_data;
};

那为什么要使用析构函数? 因为类中使用了动态内存,需要在析构函数中释放。

相对比,complex类则不需要big three,因为它类中没有使用指针,也就不存在说的这些问题。

对于拷贝赋值,copy assignment operator

inline 
String& String::operator =(const String& str) {
if (this == &str) {  // 自我赋值检测
return *this;
}

delete[] m_data;  // 先delete掉自己
m_data = new char[strlen(str.m_data) + 1)];
strcpy(m_data, str.m_data);  // friend


return *this;
}

课程还还提到了自我赋值检测,如果不做的话,一旦拷贝的是自己,不但效率上保证不了,而且会出错。因为delete掉m_data后,new的时候,长度为0;


第二周/10

扩展补充,类模版,函数模版和其他

Ø   静态变量和静态函数static

静态函数没有this pointer,只能去处理静态变量

调用静态函数的方法:通过对象调用(跟普通类一样);通过类(class name)调用。

即:

class Account {

public:

    static double m_rate;

    static voidset_rate(const double& x) {

        m_rate = x;

    }

};

使用:

Account::set_rate(5.0);

或者

Account a;

a.  set_rate(7.0); // 这种方法不同于普通对象的地方在于,它也不传this poiner给参数。

 

Static的使用例子,单例模式

详见pdf文档。

另外,static变量(包括全局和局部的)只初始化一次,

如:

void print_static() {

   static int a = 1;

   a++;

   cout << a << endl;

}

用for loop循环调用print_static十次,但a只会初始化赋值一次,所以a会从2递增到11.

Ø   Cout

cout什么可以接受这么多种数据,并且可以打印出来?

初步考虑的话,可能是因为cout做了很多重载,可以接收int, string, char等不同类型的输出。具体看它的继承:

external _IOostream_withassign cout;

class _IOostream_withassign: publicostream { }

 

正因为上面做了很多重载,所以有输出不同类型数据的效果。

 

Ø   模板(类模板class template, 和 函数模板function template)

如果不想把类型写死,可以考虑使用模板。

template <typename T>   //这一行就是告诉编译器,T还没有绑定,使用模板

定义了template,使用方法如

complex<double> c1(1, 1,);   //要明确typename绑定什么类型

complex<int> c1(1, 1,);

上面两行,编译器没看到每一行,都会重新用类型替换一次类代码。

模板会造成代码的膨胀。但膨胀是必须的。

 

函数模板

template <class T>   //class 和 typename同样效果

inline

const T& min(const T& a, constT& b) {

             returnb<a?b:a;

}

 

编译器会对函数进行实参推导,然后将template的模板函数用实际函数替换一份代码。

例子中,min函数,只负责比大小,而怎么比则是数据类型的责任。

 

模板还有更多细节,如特化,偏特化。后面再详细学习。

 

Ø   Namespace

Namespace std {    //标准库namespace

}

可以在多个文件,将多个部分的类包括在std的space中。

 

如何使用namespace,下面有三种用法

using directive  使用命令

             usingnamespace std;  //全部打开std

using declaration

             usingstd::cout;   //只打开cout

不用using,如在函数中,直接使用std::cout << 2;


0 0
原创粉丝点击