您的位置:首页 > 编程语言 > C语言/C++

C++ 类定义与操作

2016-07-13 09:03 399 查看
本文记录学习C++ primer 第六版的内容,包含C++ 11特性,主要对书中的知识点进行整理和测试,编译器采用mingw32 g++。

this指针:

成员函数通过this访问调用它的那个对象,this的目的总是指向当前的“这个”对象,所以this是一个常量指针,不能够改变this当中保存的地址。也就是this里面保存的地址,始终都是当前对象。

差不多是下面的这个意思。

Book B;
Book *const point=&B;


const成员函数:

使用常量成员函数的目的是为了不是类当中的方法改变数据成员的内容,声明方式如下。

class Book
{
public:
int a;
Book()
{
a=0;
}
int fun() const;//定义好的常量成员函数
};
//函数与的内容写成如下会报错,告诉函数中的数据内容是只读的
int Book::fun() const
{
this->a=0;
return this->a;
}
//这样定义就没有毛病
int Book::fun() const
{
return this->a;
}


常量对象,以及常量对象的引用或指针都只能调用常量成员函数。

编译器在处理成员数据和成员函数的时候首先编译成员的声明,然后才轮到成员函数体(如果有)。所以成员函数可以随意使用类中的成员,不用考虑出现次序。

这里编写一个书中的练习题,7.4 因为后面的很多例子都会用到

class Person
{
public:
string name;
string address;
string get_name() const{return this->name;}
string get_address() const {return this->address;}
};


添加输入输出

定义两个非成员函数

istream &read(istream &is,Preson &p)
{
cout<<"输入姓名和地址:"<<endl;
is>>p.name>>p.address;
return is;
}
ostream &print(ostream &os, const Preson &p)
{
os<<p.name<<" "<<p.address;
return os;
}
int main()
{
ios::sync_with_stdio(false);
Person p;
read(cin,p);
print(cout,p);
return 0;
}


这里IO类型作为参数,不能被拷贝,所以只能通过引用来传递。读取和写入操作会改变流内容么所以函数接受的是普通引用,不是常量的引用。

构造函数:

C++面向对象编程入门中比较重要的一个内容,用来初始化类中的数据成员,这也是C++语言一直遭到诟病的一个点,仅仅一个构造函数就有那么多讲究,C++无愧为最难学的编程语言。

注意点:

构造函数没有返回值

构造函数不能被声明成const函数,因为它要给数据成员赋值啊!对于建立一个const对象,这个对象也必须要完成初始化操作后才能去的const属性。因此,构造函数在const对象的构造过程中可以向其写值。

如果不在类中定义构造函数,系统会自动执行一个默认的构造函数,无须传递任何实参。

如果存在类内部的初始值,就用初始值初始化成员,否则默认初始化该成员。

如果再类中定义了一种构造函数,系统就不会提供默认构造函数。

如果一个类当中存在一个类类型的数据成员,而且这个数据成员没有默认构造函数,那就必须自定义默认构造函数,否则系统报错。

构造函数的几种写法网上已经有太多例子了,书上也非常详细,就不写了。记一下C++11提供的新特性

C++11的默认构造函数

Person()=default;


C++11类数据成员的初始化

class Screen
{
public:
typedef string::size_type pos;
Screen()=default;
Screen(pos ht,pos wd,char c):height(ht),width(wd),contents(ht*wd,c){}
char get() const {return contents[cursor];}
inline char get(pos ht,pos wd) const;
Screen &move(pos r,pos c);
void some_member() const;
private:
pos cursor=0;
pos height=0,width=0;
mutable size_t access_ctr;
string contents;
};
void Screen::some_member() const
{
++access_ctr;
}
class Window_mgr
{
private:
vector<Screen> screens{Screen(24,80,' ')};
};


上面的代码使用列表初始化的新方式。

可变数据成员

可以在常量成员函数当中被改变值的一种数据成员

class Screen
{
public:
void some_member() const;
private:
mutable size_t access_ctr;
};
void Screen::some_member() const
{
++access_ctr;
}


声明方式如上(书上的代码),这个关键字出现的目的是为了在const成员函数当中可以修改一些不相关的数据内容。

const成员函数返回*this时要注意,this指向一个const指针,所以函数返回的类型是一个常引用类型,如此将不能把返回进行一系列动作。

基于const 的重载函数时,调用哪个函数取决于你的对象是否为常量。

构造函数的初始值有时是必不可少的

如果类当中有引用成员以及常量成员等,那么我们必须将其初始化。

class ConstRef
{
public:
ConstRef(int ii);
private:
int i;
const int ci;
int &ri;
};
ConstRef::ConstRef(int ii)//报错!
{
i=ii;
ci=ii;
ri=i;
}


正确的构造函数方式应该用初始值列表拉来实现。

class ConstRef
{
public:
ConstRef(int ii):i(ii),ci(ii),ri(i){}
private:
int i;
const int ci;
int &ri;
};


这里,类中成员的初始化顺序和类中声明成员的顺序一致,不会收到构造函数顺序的影响。

委托构造函数:

这是C++11的新特性,按照我的理解,就是一个构造函数“继承”另外一个构造函数的意思。

class A
{
private:
int a;
string s;
double d;
public:
A(string ss,int aa,double dd):s(ss),a(aa),d(dd){}
A():A("",1,0.5){}//委托构造函数
A(string ss):A(ss,0,0){}//同上
};


这里第一个构造函数使用了参数初始化,下面两个构造函数,通过“继承”第一个构造函数来数据给初始化。

使用默认构造函数时需要注意,如果想要声明一个类的对象

#include <bits/stdc++.h>
using namespace std;
class A
{
public:
int a;
};
int main()
{
ios::sync_with_stdio(false);
A aa();
cout<<aa.a<<endl;//这里会报错,说aa是一个非类类型
return 0;
}


上面的代码相当于定义了一个函数,而非声明了一个对象。应该这样写才对

#include <bits/stdc++.h>
using namespace std;
class A
{
public:
int a;
};
int main()
{
ios::sync_with_stdio(false);
A aa;
cout<<aa.a<<endl;
return 0;
}


to be continue~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: