C++primer 相关学习2

1.如果一个类指定了友元类,则友元类的成员函数可以访问此类包括非公有成员在内的所有成员,友元函数也可以在类的内部定义,这样的函数是隐式内联的。

2.直到类被定义之后数据成员才能被声明成这种类类型。换句话说我们必须首先完成类的定义,然后编译器才能知道存储该数据成员需要多少空间。因为只有当类全部完成后类才算被定义,所以一个类的成员类型不能是类自己。但是一旦一个类的名字出现以后,他就被认为是声明过了(但未定义),因此类允许包含指向它自身类型的指针或者引用:

class Link_screen
{   
    Screen window;
    Link_screen *next;
    Link_screen *prev;
};

3.名字查找与类的作用域

编译器处理完类中的全部声明后才会处理成员函数的定义

4.构造函数的初始化

如果是const引用或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些成员提供初始值。
构造函数的初始值有时必不可少
如果成员是const或者是引用的话,必须对他进行初始化,而不是进行赋值。
class constref{
public:
    constref(int ii);
private:
    int i;
    const int ci;
    int &ri;
}
如果我们没有提供构造函数而是像下面这样写的话出错
constref::constref(int ii)
{
    i = ii;      //正确
    ci = ii;     //错误 不能给const 赋值
    ri = i;     //错误 ri没有被初始化
}
正确的方式应该是
constref::constref(int ii):i(ii),ci(ii),ri(i){}

5.静态成员可以适用于某些场景而普通成员不能

静态数据成员可以是不完全类型
class Bar
{
public:
            //..
private:
    static Bar mem;       //正确:静态成员可以是不完全类型
    Bar *mem1;            //正确:指针成员可以是不完全类型
    Bar mem2;             //错误:数据成员必须是完全类型
}

6.

静态成员作为默认实参
class Screen
{
private:
    static const char bkground;
public:
    Screen& clear(char = bkground);
}

7.类内只能初始化整型类型的静态常量,所以不能在类内初始化vec。

.h文件中
class E{
    static double rate = 6.5;  //错误 应该为类内静态成员变量 static constexpr double rate = 6.5;
    static const int vecsize = 20;   
    static vector<double>vec(vecsize);  //类内只能初始化整型静态变量,
}
.c文件中
double E::rate;
vector<double>E::vec;  //应该为vector<double> Example::vec(Example::vecSize);

8.Io对象无拷贝或者赋值

由于不能拷贝IO对象,因此我们也不能将形参或者返回类型设置为流类型。进行IO操作通常是以引用的方式传递和返回流,读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的

9.IO库

10.begin 返回的是普通迭代器,cbegin 返回的是常量迭代器。当不需要写访问时,应使用cbegin和cend;

11.容器元素是拷贝

当我们用一个对象来初始化容器的时候,或将一个对象插入到容器中时,实际上放入到容器中的是对象值的一个拷贝,而不是对象本身。就像是我们将一个对象传递给非引用的参数一样,容器中的元素与提供值的对象之间没有任何联系。随后对容器中的任何元素的改变都不会影响到原始对象,反之亦然。

12、访问成员函数返回的是引用

假定C是一个vector
vector<int>c;
if(!c.empty())
{
    c.front() = 42;               //将42赋予C中的第一个元素
    auto &v = c.back();           //获得指向最后一个元素的引用
    v = 1024;                     //改变c中的元素
    auto v2 = c.back();           //v2不是一个引用,他是c.back()的一个拷贝
    v2 = 0;                       //这样操作并没有影响c中的值
}

13.不要保存end返回的迭代器

auto begin = v.begin();
    end = v.end();         //保存尾迭代器是一个坏主意
while(begin!=end)
{
    ++begin;
    begin = v.insert(begin,42);
    ++begin;
}
此代码是未定义的,会导致死循环,问题在于我们将end操作返回的迭代器保存在一个名为end的局部变量中。当我们向循环中添加元素的时候,迭代器已经失效,所以在deque、string或者vector中的元素,不要缓存end 返回的迭代器

14.编写程序,从一个vector初始化一个string。

vector<char> v{ 'h', 'e', 'l', 'l', 'o' };
string str(v.cbegin(), v.cend());

15. map and set

map 是键值对,而 set 只有键没有值。当我需要存储键值对的时候使用 map,而只需要键的时候使用 set。

set 是有序不重复集合,底层实现是红黑树,而 list 是无序可重复集合,底层实现是链表。

unordered_map,它也是由哈希表实现的,而map是用红黑树实现的。

16.可以定义一个vector<int>::iterator 到int 的map 吗?list<int>::iterator  到int的map 呢?

答:可以定义一个vector  的map,但是不可以用list,因为map是排序的,键一定满足<操作,而list不满足此操作。

17const 放在一个函数的前面和后面的区别

1、int GetY() const;

2、const int * GetPosition();


对于1

该函数为只读函数,不允许修改其中的数据成员的值,也不允许调用非const成员函数。 

对于2

修饰的是返回值,表示返回的是指针所指向值是常量。

18.insert的返回值

map<string,size_t>word_count;        //从string到size_t的空map
string word;
while(cin>>word)
{   
    //插入一个元素,关键字等于word,值为1;
    //若word已经在word_count中,insert什么都不做
    auto ret = word_count.insert({word,1});
    if(!ret.second)                //word已经在word_count中
        ++ret.first->second;       //递增计数器
}

其实等价于定义
pair<map<string,size_t>::iterator,bool>ret = word_count.insert(make_pair(word,l));

定义了一个pair,第二类型为bool,第一个类型是在map<string,size_t>类型上定义的iterator类型。
若insert成功:先添加一个元素,然后返回一个 pair,pair 的 first 元素是一个迭代器。这个迭代器指向刚刚添加的元素,这个元素是 pair ,然后递增 pair 的 second 成员。 若insert失败:递增已有指定关键字的元素的 second 成员。

19.

猜你喜欢

转载自blog.csdn.net/qq_35736364/article/details/103940198
今日推荐