我们在创建类的对象时,类不应该仅仅被声明,还应该被定义过,否则无法知道类占用了多少的内存

但是如果一个类的名字已经出现过就被认为是已经声明过了,所以允许包含自己的指针或者引用。

默认构造函数:

当类中包含一个其他类的成员且它没有默认构造函数,那个编译器无法为当前类合成默认构造函数。

如果不支持内类初始值,那么所有构造函数都应显式的初始化每个内置类型成员

使用vector或string能避免分配、释放内存带来的复杂性

struct和class唯一的区别就是默认访问权限,struct(public) class(private)

初始化列表:

对象成员的初始化发生在进入构造函数本体之前,构造函数内的只能算是赋值

如果没有初始值列表显示初始化成员,会在构造函数之前执行默认初始化

(如果想创建一个常量对象,构造函数完成初始化过程,对象才真正有常量属性)。

class fo
{
public:
fo(int i);
private:
int ai;
const int ci;
int &ri;
}
fo::fo(int i)
{
ai = i;
ci = i; //error 不能给const赋值
ri = i; //error ri未初始化
}
fo::fo(int i):ai(i),ci(i),ri(i){} //correct

//如果成员是const,引用或者某需要提供默认初始值的类类型,要通过构造函数初始值列表提供。

如果构造函数没有初始值列表,那么我构造函数之前会先进行默认初始化

委托构造函数:

class sales
{
public:
sales(string s,int cnt):bookNo(s),units_sold(cnt){} //1 sales():sales("",0,0) {} //2 利用1
sales(string s):sales(s,0,0){} //3 利用1
sales(iostream &is):sales(){} //4 利用2
}

数据成员:

类内部的成员函数和友元函数是隐式内联的。

const成员函数(修改隐式this指针的类型):

所以一个成员函数被标记为const,则它不能调用一个非const的成员函数(隐式this指针,无法从const转变成非const)

class aa{
int num;
public:
void out2() const{
cout<<num<<endl;
}
void out3() const{
num+=10; //error,const函数不能修改其数据成员
cout<<num<<endl;
}
};

定义在类内部的函数是隐式inline.结构体内部this指向自己,一个常量指针.

但在const成员函数中,this会被修改成 指向常量的常量指针,所以无法修改值

编译器会首先编译成员声明,然后才是成员函数

友元

有的函数是类接口的一部分,但又不是类的成员。友元可以允许其它类或者函数访问它的非公有成员。

友元只能声明在类内部,不是类的成员所以不受它所在区域的访问控制级别的约束。

不具有传递性、不能被继承、单向无交换性

令成员函数作为友元,注意作用域:

先定义man,声明disp不定义。在disp使用woman前声明它。

定义woman然后disp的友元声明。

定义disp

//成员函数的friend声明必需在定义之前,需要用到类限定符。所以man必须先被定义
class woman; // 前向声明
class man
{
public:
void disp(woman &w);
};
class woman
{
public:
friend void man::disp(woman &w); // 将man的其中一个成员函数disp()设为woman的友元函数,就可以使用该函数访问woman对象的私有成员了 private:
string name;
};
void man::disp(woman &w)
{
cout << w.name << endl;
}

类和非成员函数的声明不是必须在它们的友元声明之前。

struct X
{
friend void f() {]
X(){ f(); }
void g();
void h();
}
void X::g(){ return f(); }
void f();
void X::h(){ return f(); }

如果想把一组重载声明为友元,必需对戏中的每一个分别声明

可变数据成员:

有时候希望改变const对象里面的某个数据成员,可通过在数据成员加上mutable实现。

而一个可变的数据成永远不可能是const

mutable size_t acces;

返回*this的成员函数:

返回引用和非引用的区别

class Screen
{
public:
Screen &set(char);
Screen &move(int ,int);
};
inline Screen& Screen::set(char c){}
inline Screen& Screen::move(int x,int y){}
int main()
{
Screen myScreen;
myScreen.move(4,0).set('#'); myScreen.move(4,0); //如果返回引用,等效于此
myScreen.set('#'); Screen temp = myScreen.move(4,0); //如果返回非引用。。,则是一个副本
temp.set('#');
}

const成员返回*this时,不能嵌入一个动作序列

如果display返回常量引用,调用set则会产生错误。。无法修改一个常量对象

基于const的重载:

如果某个对象上面调用display,该对象是否是const决定了调用display的那个版本

Class A {
int display();
int display() const;
};

原因是:按照函数重载的定义,函数名相同而形参表有本质不同的函数称为重载。在类中,由于隐含的this形参的存在,const版本的 display函数使得作为形参的this指针的类型变为指向const对象的指针

不完全类型:

一旦一个类名出现,就被认为是声明过了(但尚未定义),因此允许包含自己的指针。

在声明之后,定义之前是一个不完全类型。

①可以定义指向这个的指针和引用 ②也可以声明以不完全类型作为参数或者返回类型的函数

class Link_screen
{
Screen windows;
Link_screen *next;
}

作用域:

一旦遇到类名,那么剩下的部分就在类的作用域之内了(参数列表和函数体)

class Window_mgr
{
public:
ScreenIndex addScreen(const Screen&);
};
Window_mgr::ScreenIndex
Window_mgr::addScreen(const Screen& a)
{}

对于类成员函数的名字查找:

1.编译成员的声明 2.直到类全部可见之后才编译函数体

class Account         //balance会在整个类可见之后才被处理
{
public:
int balance(){return val;}
private:
int val;
}

类型名:

通常内层作用域可以重新定义作用域外的名字,即便这个已经被用过。

但是在类中,如果使用外层作用域的某个名字,而这名字代表一种类型,则不能重新定义

typedef double mon;
class Account{
public:
mon balance(){};
private:
typedef double mon; //不能重新定义mon
}

成员定义的普通块作用域的名字查找:

1.先成员函数内部 2.类内全面查找 3.成员函数定义之前的作用域

所以此例中生效的是pos height,但是它隐藏了同名的成员,对于被隐藏对象可以通过作用域符 ::

int height;
class Screen{
public:
typedef std::string::size_type pos;
void dup(pos height)
{
cursor = width*height; //width*this->height,不建议隐藏同名
}
private:
pos height = 0,width = 0;
pos curson;
}

类类型转换:

隐式转换:

能通过一个参数的拷贝构造函数定义一条从构造函数参数类型到类类型的隐式转换规则。

(只有一个实参的能用于隐式转换)

struct foo
{
foo(){}
foo(int a):real(a){}
// int b = 2;
const foo& operator+(foo c){
return foo(this->real + c.real);
}
int real;
}; int main()
{
foo f;
f = 10; //会生成一个临时的foo
cout <<f.real <<endl;
f = f + 100;
cout << f.real <<endl;
}

只允许一步转换:

string->foo   correct
"9999"->string->foo error
item.combine("9999"); //error
item.combine(string("9999")); //correct 显式转换string,隐式转换
item.combine(sales("9999")); //correct 隐式转换string,显式转换sales

我们可以通过将构造函数声明为explicit阻止隐式转换,函数只能用于直接初始化

(只类内部的声明时使用,在类外定义时不需要重复explicit)

struct node
{
explicit node(){}
explicit node(string s){}
node& combine(node &b){}
};
int main()
{
string s = "xxx";
node a("xxx");
node b(s);
//node a = s; //error 没法隐式的创建对象node
//a.combine(s); //error
}

静态成员:

static将其与类绑定起来。在类外定义时不能重复static.一般来说不能在类内定义初始化静态成员(可能产生重复定义)

如果静态成员是constexpr类型并且初始值是常量表达式,可以在类内进行定义。

而且由于静态成员函数不与对象绑定,不包含this指针,所以也不能被声明为const

因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了

class Point
{
public:
void init()
{
}
static void output()
{
printf("%d\n", m_x); //error
}
private:
int m_x;
};
int main()
{
Point pt;
pt.output();
}

static数据成员,不可被定义在inline函数中.inline函数在编译时会被编译为2进制代码并重复嵌入各函数体中,而static类型数据成员只可被初始化一次,inline函数中使用static的话,将会造成static类型数据成员被多次初始化错误.

静态成员可以是不完全类型,静态成员可以作为默认实参

class Screen
{
public:
Screen &clear(char = back);
private:
static const char back;
};

C++Primer学习——类的更多相关文章

  1. C++ Primer学习笔记(三) C++中函数是一种类型!!!

    C++中函数是一种类型!C++中函数是一种类型!C++中函数是一种类型! 函数名就是变量!函数名就是变量!函数名就是变量! (---20160618最新消息,函数名不是变量名...囧) (---201 ...

  2. C++ Primer学习笔记(二)

    题外话:一工作起来就没有大段的时间学习了,如何充分利用碎片时间是个好问题. 接  C++ Primer学习笔记(一)   27.与 vector 类型相比,数组的显著缺陷在于:数组的长度是固定的,无法 ...

  3. 深入java虚拟机学习 -- 类的加载机制(续)

    昨晚写 深入java虚拟机学习 -- 类的加载机制 都到1点半了,由于第二天还要工作,没有将上篇文章中的demo讲解写出来,今天抽时间补上昨晚的例子讲解. 这里我先把昨天的两份代码贴过来,重新看下: ...

  4. 深入java虚拟机学习 -- 类的卸载

    类的生命周期 在开始本节之前让我们再来回顾下类的生命周期 没看过前6个过程的同学建议从头看下<深入java虚拟机学习 -- 类的加载机制>,这里就不再过多介绍了,着重说下类的卸载 类的卸载 ...

  5. Swift学习——类的定义,使用,继承,构造等(五)

    Swift学习--类的定义,使用.继承,构造等(五) 类的使用说明 1 使用class和类名来创建一个类名,比如: class student 2 类中属性的声明和常量和变量一样,唯一的差别就是他们的 ...

  6. c++ primer 学习杂记2【派生类到基类转换的可访问性】

    参考: http://blog.csdn.net/rehongchen/article/details/7930853 http://blog.csdn.net/ming_road/article/d ...

  7. C++ Primer 学习笔记_69_面向对象编程 --继承情况下的类作用域

    面向对象编程 --继承情况下的类作用域 引言: 在继承情况下,派生类的作用域嵌套在基类作用域中:假设不能在派生类作用域中确定名字,就在外围基类作用域中查找该名字的定义. 正是这样的类作用域的层次嵌套使 ...

  8. C++ Primer 学习笔记_57_类和数据抽象 --管理指针成员

    复印控制 --管理指针成员 引言: 包括指针的类须要特别注意复制控制.原因是复制指针时.一个带指针成员的指针类 class HasPtr { public: HasPtr(int *p,int i): ...

  9. C++ Primer 学习笔记_53_类和数据抽象 --友元、static员

    分类 --友元.static成员 一.友元 友元机制同意一个类将对其.友元关系:一个样例 如果一个窗体管理类Window_Mgr可能须要訪问由其管理的Screen对象的内部数据.Screen应该同意其 ...

随机推荐

  1. pjax实例demo(c#,iis)

    pjax 百度都是api 也没找到demo 自己写了一个 C#写的 需要iis架设 测试ie10 和 火狐 成功 ie10不要用兼容模式 不然不好使 iis 可以直接架设webDemo1文件夹(源码) ...

  2. 推荐net开发cad入门阅读代码片段

    转载自  Cad人生  的博客 链接:http://www.cnblogs.com/cadlife/articles/2668158.html 内容粘贴如下,小伙伴们可以看看哦. using Syst ...

  3. 【非官方】Surging 微服务框架使用入门

    前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正. 我对 surging 的看法 我目前所在的公司采用架构就是类似与Surging的RPC框架,在.NET 4.0框架 ...

  4. sql2008r2,以前好好可以用的,但装了vs2017后,连接不上了,服务也停了,结果手动也 启动不了, 无法加载或初始化请求的服务提供程

    日志: 2017-12-14 12:33:17.53 服务器 A self-generated certificate was successfully loaded for encryption.2 ...

  5. windows 10下通过python3.6成功搭建jupyter 服务器

    最近通过python学习爬虫技术,发现一个工具jupyter notebook很不错,该工具明显优势通过浏览器可以输入多行python代码,支持在线运行以及运行结果保存功能,在线验证python小模块 ...

  6. Python爬虫之urllib模块1

    Python爬虫之urllib模块1 本文来自网友投稿.作者PG,一个待毕业待就业二流大学生.玄魂工作室未对该文章内容做任何改变. 因为本人一直对推理悬疑比较感兴趣,所以这次爬取的网站也是平时看一些悬 ...

  7. JAVA 中一个非常轻量级只有 200k 左右的 RESTful 路由框架

    ICEREST 是一个非常轻量级只有 200k 左右的 RESTful 路由框架,通过 ICEREST 你可以处理 url 的解析,数据的封装, Json 的输出,和传统的方法融合,请求的参数便是方法 ...

  8. Java设计模式(七)Decorate装饰器模式

    一.场景描述 (一)问题 系统中最初使用Crystal Report(水晶报表)工具生成报表,并将报表发送给客户端查看,此时定义一CrystalReport工具类即可完成水晶报表的生成工作. 后续报表 ...

  9. 表单提交中的input、button、submit的区别

    1.input[type=submit] 我们直接来看例子: 代码如下: <form> <input name="name"> <input type ...

  10. Dictionary导致CPU暴涨

    中午吃完饭回来,刚想眯一会,突然发现公司预警群报警,某台机器CPU100%,连续三次报警,心里咯噔一下,我新开发的程序就在这上面,是不是我的程序导致的?立马远程,oh my god,果然是. 二话不说 ...