1、h是class定义
cpp 是实现
带main的cpp是调用
2、调h里面的namespace里面的数据或者算法
古怪
1、this是对象的address,对象本身是 *this
2、括号中的const表明改函数不会修改被显式访问的对象;括号后的const表明,不会修改被隐式访问的对象,即 *this。因为返回了两个const对象之一的引用,因此返回类型也应为const引用
const Stock & Stock::topval(const Stock & s) const
{
if(s.total_val >total_val)
return s;
else
return *this;
}
total = coding.operator+(fixing);
//将方法命令为operator+()后,也可以使用运算符表示:
total = coding + fixing;
//先有上面的操作符简化的书写方式,然后引出问题头一个参数必须是对象
//引出解决方法---非成员函数访问类的私有成员,即为友元函数 friend
//作用是用在运算符重载的时候第一个参数不用必须是类对象了
//定义类特定的常量,if他们是整数,enum提供了一种方便的途径
enum {fck=14};
//当然can this way
static const int fck=14;
复制构造函数用于将一个对象复制到新创建的对象中。也包括按值传递参数和返回对象
//将对象作为函数参数按值传递的时候会调用对象的复制构造函数,所以析构函数会比构造函数多调用一次
//https://blog.csdn.net/yangkunqiankun/article/details/74885784
StringBad sailor = sports;//这使用的是哪个构造函数呢?不是默认的,也不是带参数你定义的
//上面的代码等同于
StringBad sailor = StringBad(sports);
//当你使用一个对象初始化另一个对象时,编译器将自动生成上述构造函数
//(即复制构造函数,因为它创建对象的一个副本)
//所有问题的罪魁祸首就是这种构造函数(编译器自动生成的成员函数)
浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。 深复制:在计算机中开辟一块新的内存地址用于存放复制的对象
如果类中包含了使用new初始化的指针成员,应当定义一个复制构造函数
temp[0]=='\0';// empty line
Act *pt = new Act;
delete pt; //delete释放的是保存pt指针的空间,析构函数释放的是pt指向的内存空间
析构函数的调用时机(p472)
1、如果对象是动态变量,则当执行完定义该对象的程序块时,调用析构
2、如果对象时静态变量,则在程序结束时调用
3、new出来的,delete的时候调用
int &b=a; //引用,注意传参的时候也是引用
int *p=&a; //取地址
和类型在一起的是引用,和变量在一起的是取址
class A {...} //声明一个 类 A
void *buf = malloc(sizeof(A)); //简单地分配空间。
A *ojb = new (buf)A(); // 在分配的空间上调用构造函数。
//现在问题来了: 这里 的空间可以是任意的空间吗,答案是的!
//这里的 “已经分配好的空间” 可以是任何的空间,比如说 可以是栈上的空间!
class A {int a;}
int buf[sizeof(A)]; //在栈上,分配一个数组
A *obj = new(buf) A(); //在这个数组上构造一个 对象 A。
-------------------------
定位new的格式为
new(args) T
其中,args是一个对象的指针,即指定的起始地址;T是分配内存的类型;返回值也是指定的起始地址。
char x[sizeof(MyClass)];
MyClass* fPtr2 = new(&x[0])MyClass;
通过定位new分配的内存就是在数组x的起始地址上。
释放内存
由于定位new分配的内存并不是“新分配”的,而是原先就有的。所以不能使用delete来释放该内存,而是要通过析构函数来释放资源。
fPtr2->~MyClass();
//成员初始化列表 several 种语法
//类名和构造函数
TableTennis::TableTennis(const string & fn,bool ht):firstname(fn),hasTable(ht){}
TableTennis::TableTennis(const string & fn,bool ht)
{
firstname=fn;
hasTable=ht;
}
//derived class 派生类
派生类不能直接访问基类的私有数据,必须使用基类的共有方法才可以。构造函数使用一种技术,其他成员函数是另一种技术
1、派生类构造函数初始化基类私有数据时,采用的是成员初始化列表语法
RatedPlayer::RatedPlayer(unsigned int r,const string & fn,const string & ln,bool ht):TableTennisPlayer(fn,ln,ht)
{
rating = r;
}
对于成员对象,构造函数则使用成员名
Student(const char * str, const double * pd, int n):name(str), scores(pd, n) {}
虚析构函数的重要性:
Brass是基类,BrassPlus是派生类
Brass *p_clients[5];
如果析构函数不是虚的,那么只调用Brass的析构函数,不调用BrassPlus.所以设成虚函数那么就会先调BrassPlus的析构函数,然后再是Brass的
//p541
//赋值运算符原型
Star & Star::operator=(const Star &);
赋值运算符函数返回一个Star对象引用。
编译器不会生成将一种类型赋给另一种类型的赋值运算符。如果希望能将字符串赋给Star对象,
Star & Star::operator=(const char *) {...}
转换函数
Star::Star double() {...} //converts star to double
//converts to const char
Star::Star const char * () {...}
// returns a Star object
Star nova1(const Star &);
// returns a reference to a Star
Star & noval2(const Star &);
直接返回对象一般用在返回临时对象,(参考按值传递和按引用传递,复制函数)
Vector Vector::operator+(const Vector & b) const
{
return Vector(x + b.x, y + b.y);
}
// 确保方法不修改参数
Star::Star(const char * s) {...}
// 确保方法不修改调用它的对象
void Star::show() const {...}
// 确保返回值不被修改
const Stock & Stock::topval(const Stock & s) const
在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
纯虚函数不在父类中实现,必须在子类中实现
纯虚函数只有定义,没有实现;而虚函数既有定义,也有实现的代码。
含有纯虚拟函数的类称为抽象类,包含纯虚函数的类不能定义其对象,而包含虚函数的则可以
void show(const Brass & rba)
{
rba.ViewAcct();
}
void inadequate(Brass ba)
{
ba.ViewAcct();
}
BrassPlus buzz("Buzz P",4300);
show(buzz);//因为是引用,所以buzz解释为BrassPlus版本
inadequate(buzz);//按值传递,只有buzz的Brass部分被显示
valarray是模板类 P552 《C++ Primer Plus》
声明对象语法 valarray<int> q_values; // an array of int
operator[]():让您能够访问各个元素
explicit用于防止构造函数隐式转换,比如给一个对象赋值int值,
编译器就会告诉你int不能隐式成这个对象
类模板就是可以将类型作为参数传递给这个类,产生一个类通用的作用
模板的作用就让程序员可以复用一些经过测试的代码
1、如果指向的对象(*pt)的类型为Type或者是从Type直接或间接派生而来的类型,
则下面的表达式将指针pt转换为Type类型的指针:
dynamic_cast<Type *>(pt)
否则,结果为0,即空指针
2、如果pg指向的是一个Magnificent对象,则下述表达式的结果为bool值true,否则为false:
typeid(Magnificent) == typeid(*pg)
智能指针模板的作用:自动释放动态内存。(auto_ptr, shared_ptr, unique_ptr)