再次学习C++类之构造函数
学习C++类,首先要说C中的结构体,虽然C++类扩展了C中的结构体,可以添加成员函数,但他们是有区别的。在结构体中,成员变量、成员函数都是公有的,而类中,一般是成员变量是私有的,成员函数是公有的,私有的成员变量一般对象不可调用(数据隐藏),只能是成员函数来调用。
代码1:
#include <iostream>
using namespace std; class MyClass
{
private:
int m_value;
public:
int get();
void set(int n);
}; int MyClass::get()
{
return m_value;
} void MyClass::set(int n)
{
m_value=n;
} int main()
{
MyClass myclass;
//cout<<myclass.m_value<<endl;
cout<<myclass.get()<<endl; myclass.set();
cout<<myclass.get()<<endl;
return ;
}
如果没有注释掉26行,编译时会出现error C2248: 'm_value' : cannot access private member declared in class 'MyClass',即应证了类中的私有成员变量只能通过公有成员函数调用,对象是不能直接获取的。
执行27行后,显示的是一个不确定的负数,其实,执行25行的MyClass myclass;后编译系统为对象myclass的数据成员(m_value)分配内存空间,并调用默认构造函数MyClass( )自动地初始化对象myclass的m_value值设置为一不确定的值。当然,我们也可以自己设计构造函数。
构造函数主要可以分为如下几种形式:
无参数构造函数 如果创建一个类你没有写任何构造函数,则系统会自动生成默认的无参构造函数,函数为空,什么都不做。只要你写了一个下面的某一种构造函数,系统就不会再自动生成这样一个默认的构造函数,如果希望有一个这样的无参构造函数,则需要自己显示地写出来;
一般构造函数(也称重载构造函数) 一般构造函数可以有各种参数形式,一个类可以有多个一般构造函数,前提是参数的个数或者类型不同(基于c++的重载函数原理)。 创建对象时根据传入的参数不同调用不同的构造函数;
复制构造函数(也称为拷贝构造函数) 复制构造函数参数为类对象本身的引用,用于根据一个已存在的对象复制出一个新的该类的对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中.若没有显示的写复制构造函数,则系统会默认创建一个复制构造函数,但当类中有指针成员时,由系统默认创建该复制构造函数会存在风险,具体原因请查询 有关 “浅拷贝” 、“深拷贝”的文章论述.
代码2
#include <iostream>
using namespace std; class MyClass
{
private:
int m_value;
public:
MyClass(){m_value=;} //无参构造函数
MyClass(int n){m_value=n;} //一般构造函数
MyClass(const MyClass &my){m_value=my.m_value;} //复制构造函数
int get();
void set(int n); }; int MyClass::get()
{
return m_value;
} void MyClass::set(int n)
{
m_value=n;
} int main()
{
MyClass myclass1;
cout<<myclass1.get()<<endl; MyClass myclass2();
//MyClass myclass2=MyClass(4);
cout<<myclass2.get()<<endl; MyClass myclass;
MyClass myclass3(myclass);
cout<<myclass3.get()<<endl; return ;
}
代码2分别定义了无参构造函数、一般构造函数和复制构造函数。在主函数中,29行调用了无参构造函数,32行调用了一般构造函数,且它的作用等价注释掉的33行,37行调用了复制构造函数,即通过对象myclass来创建对象myclass3。
其实对于无参构造函数、一般构造函数还有另一种形式:
queue(int qs):qsize(qs),items(0),front(NULL),rear(NULL){}
即由冒号和逗号分隔的初始化列表,被放在构造函数参数的右括号后,函数体的左括号之前。
代码3
#include <iostream>
using namespace std; class MyClass
{
private:
int m_value;
public:
MyClass(int n){m_value=n;}
int get();
void set(int n);
void show();
}; int MyClass::get()
{
return m_value;
} void MyClass::set(int n)
{
m_value=n;
} void MyClass::show()
{
cout<<m_value<<endl;
} int main()
{
MyClass myclass1();
myclass1.show(); MyClass myclass2=myclass1;
myclass2.show(); return ;
}
在代码3中,32行调用自定义的构造函数创建对象myclass1,而35行,却是调用的系统默认的复制构造函数,即系统为对象myclass2 分配了内存并完成了与对象myclass1 的复制过程.编译系统的机制是,如果系统类没有自己定义复制构造函数,会采用默认的,如果自己定义了,则会用定义的,其实代码3和代码4(自定义)的作用和效果是相同的。
代码4
#include <iostream>
using namespace std; class MyClass
{
private:
int m_value;
public:
MyClass(int n){m_value=n;}
MyClass(const MyClass &my){m_value=my.m_value;}
int get();
void set(int n);
void show();
}; int MyClass::get()
{
return m_value;
} void MyClass::set(int n)
{
m_value=n;
} void MyClass::show()
{
cout<<m_value<<endl;
} int main()
{
MyClass myclass1();
myclass1.show(); MyClass myclass2=myclass1;
myclass2.show(); return ;
}
代码4中10行就是我们自定义的复制构造函数,复制构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量,且没有其他参数或其他参数都有默认值。
复制构造函数用于将一个对象复制到新创建的对象中,也就是说,它用于初始化过程中(包括按值传递参数),而不是常规的赋值过程中。
那么什么时候需要一般的构造函数,什么时候需要复制构造函数:总的来说,以下三种情况需要复制构造函数,具体:
1. 对象以值传递的方式传入函数参数
2. 对象以值传递的方式从函数返回
3. 对象需要通过另外一个对象进行初始化
其实以上代码中的复制构造函数就是所谓的浅拷贝,即只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。大多情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员或静态成员,那么浅拷贝就会出问题。
再次学习C++类之构造函数的更多相关文章
- 再次学习 java 类的编译
		
做JAVA开发的都知道myeclipse, 我们在myeclipse中新建一个类,然后保存, 如何正常的话,那么在项目指定的目录(也就是项目的output目录)就会生成同名的class文件, 可是,我 ...
 - 【C++学习之路】派生类的构造函数(一)
		
一.简单派生类的构造函数 1.所谓简单派生类,就是指派生类中不包含基类的内嵌对象的派生类. 2.一般来说,这样的派生类的构造函数的形式是: student( int i, string nam, in ...
 - C++学习17派生类的构造函数
		
基类的构造函数不能被继承,在声明派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数来完成.所以在设计派生类的构造函数时,不仅要考虑派生类新增的成员变量,还要考虑基类的成员变量,要让它们都 ...
 - 【C++学习之路】组合类的构造函数
		
1 #include <iostream> using namespace std; class A { public: A(){ cout << "调用A无参&qu ...
 - 【C++学习之路】派生类的构造函数(三)
		
三.多层继承的派生类 1.多层继承的派生类只需在构造函数的初始化列表中写出直接基类的构造函数即可 class student { public: student(int n, string nam) ...
 - 【C++学习之路】派生类的构造函数(二)
		
二.有内嵌对象的派生类 1.一般来说,我们会这样定义构造函数 student( int i, string nam, int pid, string pnam, int sid) : person( ...
 - C++学习之路—继承与派生(二):派生类的构造函数与析构函数
		
(根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 由于基类的构造函数和析构函数是不能被继承的,所以 ...
 - C++学习笔记(6)----基类和派生类的构造函数和析构函数的执行顺序
		
基类和派生类:构造函数和析构函数的执行顺序 在Visual Studio中,新建控制台工程,构造类如下: #include<iostream> using namespace std; c ...
 - c++学习笔记4,派生类的构造函数与析构函数的调用顺序(一)
		
測试源代码: //測试派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include <iostream> using namespace ...
 
随机推荐
- Spreadsheet Tracking
			
Spreadsheet Tracking Data in spreadsheets are stored in cells, which are organized in rows (r) and ...
 - Python性能测试
			
python -m profile xxx.py > log.txt 打开log.txt查看,搜索你所关心的方法调用耗费的时间. profile的统计结果分为ncalls.tottime.per ...
 - Magento事件机制 - Magento Event/Observer
			
为了扩展Magento的功能,我们可以重写Magento的代码,但因为代码只能被重写一次,所以当多个模块需要重写同一部分的代码时,就会引起冲突,好在Magento提供了另一种扩展功能的方法:事件机制, ...
 - webstorm卡、闪退以及win10中jdk配置【转】
			
原文地址:webstorm卡.闪退以及win10中jdk配置 今天 webstorm 突然一直处于 indexing 索引状态,然后就卡死,重装也无法解决. 搜了一下后,有人说使用 64 位客户端 ...
 - 关于easyui的一些小知识点(1)
			
让layout布局自动适应浏览器宽度只需要加上fit="true"属性.
 - UML——动态建模
 - C# WCF学习笔记(二)终结点地址与WCF寻址(Endpoint Address and WCF Addressing) WCF中的传输协议
			
URI的全称是 Uniform Rosource Identifire(统一资源标识),它唯一标识一个确定的网绐资源,同时也表示资源所处的位置及访问的方式(资源访问所用的网络协议). 对于Endpoi ...
 - python - 图例显示中文
			
# -*- coding: utf-8 -*- """ Created on Mon Nov 30 13:24:00 2015 @author: jx_luo " ...
 - Unity连接本地数据库sqlite
			
首先要创建一个sqlite的数据库,记住文件地址,拷贝到Assets目录下,创建的数据库文件后缀为.sqlite.具体创建方法百度sqlite 然后百度Mono.Data.Sqlite,这是一个dll ...
 - 操作Excel导入的问题(转)
			
当Excel导入成为需要时,之前的导出Excel为html方式的方法就受阻了,于是,需要开始新的百度与google来解决问题. 前提为OLEDB+Excel. 根据需求,多数是对于表的数据的导入.于是 ...