C++ 复制构造函数

C++ 复制构造函数,第1张

拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的参数(对象的引用)是不可变的(const类型)。此函数经常用在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。

目录

拷贝构造函数说明

一、拷贝函数

二、值的重载

三、注意事宜

四、拷贝构造与构造区别

展开

编辑本段

拷贝构造函数说明

调用拷贝构造函数的情形

在C++中,下面三种对象需要调用拷贝构造函数:

1) 一个对象以值传递的方式传入函数体;

2) 一个对象以值传递的方式从函数返回;

3) 一个对象需要通过另外一个对象进行初始化;

如果在前两种情况不使用拷贝构造函数的时候,就会导致一个指针指向已经被删除的内存空间。对于第三种情况来说,初始化和赋值的不同含义是构造函数调用的原因。事实上,拷贝构造函数是由普通构造函数和赋值 *** 作符共同实现的。描述拷贝构造函数和赋值运算符的异同的参考资料有很多。

拷贝构造函数不可以改变它所引用的对象,其原因如下:当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,这会导致无限循环直至栈溢出(Stack Overflow)。除了当对象传入函数的时候被隐式调用以外,拷贝构造函数在对象被函数返回的时候也同样的被调用。

隐式的拷贝构造函数

如果在类中没有显式的声明一个拷贝构造函数,那么,编译器会自动生成一个来进行对象之间的位拷贝(Bitwise Copy)。这个隐含的拷贝构造函数简单的关联了所有的类成员。注意到这个隐式的拷贝构造函数和显式声明的拷贝构造函数的不同在于对成员的关联方式。显式声明的拷贝构造函数关联的只是被实例化的类成员的缺省构造函数,除非另外一个构造函数在类初始化或构造列表的时候被调用。

拷贝构造函数使程序更有效率,因为它不用再构造一个对象的时候改变构造函数的参数列表。设计拷贝构造函数是一个良好的风格,即使是编译系统会自动为你生成默认拷贝构造函数。事实上,默认拷贝构造函数可以应付许多情况。

示例

以下讨论中将用到的例子:

class CExample

{

public:

CExample(){pBuffer=NULLnSize=0}

~CExample(){delete pBuffer}

void Init(int n){ pBuffer=new char[n]nSize=n}

private:

char *pBuffer//类的对象中包含指针,指向动态分配的内存资源

int nSize

}

这个类的主要特点是包含指向其他资源的指针。

pBuffer指向堆中分配的一段内存空间。

编辑本段

一、拷贝函数

int main(int argc, char* argv[])

{

CExample theObjone

theObjone.Init(40)

//现在需要另一个对象,需要将他初始化称对象一的状态

CExample theObjtwo=theObjone

...

}

语句"CExample theObjtwo=theObjone"用theObjone初始化theObjtwo。

其完成方式是内存拷贝,复制所有成员的值。

完成后,theObjtwo.pBuffer==theObjone.pBuffer。

即它们将指向同样的地方,指针虽然复制了,但所指向的空间并没有复制,而是由两个对象共用了。这样不符合要求,对象之间不独立了,并为空间的删除带来隐患。所以需要采用必要的手段来避免此类情况。

回顾一下此语句的具体过程:首先建立对象theObjtwo,并调用其构造函数,然后成员被拷贝。

可以在构造函数中添加 *** 作来解决指针成员的问题。

所以C++语法中除了提供缺省形式的构造函数外,还规范了另一种特殊的构造函数:拷贝构造函数,上面的语句中,如果类中定义了拷贝构造函数,这对象建立时,调用的将是拷贝构造函数,在拷贝构造函数中,可以根据传入的变量,复制指针所指向的资源。

拷贝构造函数的格式为:构造函数名(对象的引用)

提供了拷贝构造函数后的CExample类定义为:

class CExample

{

public:

CExample(){pBuffer=NULLnSize=0}

~CExample(){delete pBuffer}

CExample(const CExample&)//拷贝构造函数

void Init(int n){ pBuffer=new char[n]nSize=n}

private:

char *pBuffer//类的对象中包含指针,指向动态分配的内存资源

int nSize

}

CExample::CExample(const CExample&RightSides) //拷贝构造函数的定义

{

nSize=RightSides.nSize//复制常规成员

pBuffer=new char[nSize]//复制指针指向的内容

memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof(char))

}

这样,定义新对象,并用已有对象初始化新对象时,CExample(const CExample&RightSides)将被调用,而已有对象用别名RightSides传给构造函数,以用来作复制。原则上,应该为所有包含动态分配成员的类都提供拷贝构造函数。

下面介绍拷贝构造函数的另一种调用。当对象直接作为参数传给函数时,函数将建立对象的临时拷贝,这个拷贝过程也将调同拷贝构造函数。例如:

BOOL testfunc(CExample obj)

testfunc(theObjone)//对象直接作为参数。

BOOL testfunc(CExample obj)

{

//针对obj的 *** 作实际上是针对复制后的临时拷贝进行的

}

还有一种情况,也是与临时对象有关的

当函数中的局部对象被被返回给函数调者时,也将建立此局部对象的一个临时拷贝,拷贝构造函数也将被调用

CTest func()

{

CTest theTest

return theTest

}

编辑本段

二、值的重载

下面的代码与上例相似

int main(int argc, char* argv[])

{

CExample theObjone

theObjone.Init(40)

CExample theObjthree

theObjthree.Init(60)

//现在需要一个对象赋值 *** 作,被赋值对象的原内容被清除,并用右边对象的内容填充。

theObjthree=theObjone

return 0

}

也用到了"="号,但与"一、"中的例子并不同,"一、"的例子中,"="在对象声明语句中,表示初始化。更多时候,这种初始化也可用括号表示。

例如 CExample theObjone(theObjtwo)

而本例子中,"="表示赋值 *** 作。将对象theObjone的内容复制到对象theObjthree,这其中涉及到对象theObjthree原有内容的丢弃,新内容的复制。

但"="的缺省 *** 作只是将成员变量的值相应复制。旧的值被自然丢弃。

由于对象内包含指针,将造成不良后果:指针的值被丢弃了,但指针指向的内容并未释放。指针的值被复制了,但指针所指内容并未复制。

因此,包含动态分配成员的类除提供拷贝构造函数外,还应该考虑重载"="赋值 *** 作符号。

类定义变为:

class CExample

{

...

CExample(const CExample&)//拷贝构造函数

CExample&operator = (const CExample&)//赋值符重载

...

}

//赋值 *** 作符重载

CExample &CExample::operator = (const CExample&RightSides)

{

if (this == &RightSides) // 如果自己给自己赋值则直接返回

{

return *this

}

nSize=RightSides.nSize//复制常规成员

char *temp=new char[nSize]//复制指针指向的内容

memcpy(temp,RightSides.pBuffer,nSize*sizeof(char))

delete []pBuffer//删除原指针指向内容(将删除 *** 作放在后面,避免X=X特殊情况下,内容的丢失)

pBuffer=NULL

pBuffer=temp//建立新指向

return *this

}

编辑本段

三、注意事宜

拷贝构造函数和赋值函数的功能是相同的,为了不造成重复代码,拷贝构造函数实现如下:

CExample::CExample(const CExample&RightSides)

{

*this=RightSides//调用重载后的"="

}

编辑本段

四、拷贝构造与构造区别

class 类名

{

public:

类名(形参参数)//构造函数

类名(类名&对象名)//拷贝构造函数

,,,,,,,,,,,,,,,,,,,,,

}

拷贝构造函数的实现:

类名::类名(类名&对象名)//拷贝构造函数的实现

{函数体}

不完整的例子

拷贝构造函数:

Class Point

{

Public:

Point(int xx=0,int yy=m)(X=xxY=yy)

Point(Point&p)

Int getX() {return X;}

Int getY(){ return Y}

Private :

Int X,Y

}

Point::Point(Point&p)

{

X=p.X

Y=p.Y

Cout<<"拷贝构造函数调用"<<endl

}

构造函数

构造函数 是一种特殊的方法 主要用来在创建对象时初始化对象 即为对象成员变量赋初始值

总与new运算符一起使用在创建对象的语句中 特别的一个类可以有多个构造函数 可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载

构造函数与其他方法的区别

1.构造函数的命名必须和类名完全相同而一般方法则不能和类名相同.

2.构造函数的功能主要用于在类的对象创建时定义初始化的状态.它没有返回值,也不能用void来修饰.这就保证了它不仅什么也不用自动返回,而且根本不能有任何选择.而其他方法都有返回值.即使是void返回值,尽管方法体本身不会自动返回什么,但仍然可以让它返回一些东西,而这些东西可能是不安全的.

3.构造函数不能被直接调用,必须通过new运算符在创建对象时才会自动调用,一般方法在程序执行到它的时候被调用.

4.当定义一个类定义的时候,通常情况下都会显示该类的构造函数,并在函数中指定初始化的工作也可省略不去Java编译器会提供一个默认的构造函数.此默认构造函数是不带参数的.而一般方法不存在这一特点

拷贝构造函数

拷贝构造函数,经常被称作X(X&),是一种特殊的构造函数,他由编译器调用来完成一些基于同一类的其他对象的构件及初始化。它的唯一的一个参数(对象的引用)是不可变的(因为是const型的)。这个函数经常用在函数调用期间于用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。

在C++中,下面三种对象需要拷贝的情况。因此,拷贝构造函数将会被调用。

1). 一个对象以值传递的方式传入函数体

2). 一个对象以值传递的方式从函数返回

3). 一个对象需要通过另外一个对象进行初始化

以上的情况需要拷贝构造函数的调用。如果在前两种情况不使用拷贝构造函数的时候,就会导致一个指针指向已经被删除的内存空间。对于第三种情况来说,初始化和赋值的不同含义是构造函数调用的原因。事实上,拷贝构造函数是由普通构造函数和赋值 *** 作赋共同实现的。描述拷贝构造函数和赋值运算符的异同的参考资料有很多。

拷贝构造函数不可以改变它所引用的对象,其原因如下:当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,这会导致无限循环。

除了当对象传入函数的时候被隐式调用以外,拷贝构造函数在对象被函数返回的时候也同样的被调用。换句话说,你从函数返回得到的只是对象的一份拷贝。但是同样的,拷贝构造函数被正确的调用了,你不必担心。

如果在类中没有显式的声明一个拷贝构造函数,那么,编译器会私下里为你制定一个函数来进行对象之间的位拷贝(bitwise copy)。这个隐含的拷贝构造函数简单的关联了所有的类成员。许多作者都会提及这个默认的拷贝构造函数。注意到这个隐式的拷贝构造函数和显式声明的拷贝构造函数的不同在于对于成员的关联方式。显式声明的拷贝构造函数关联的只是被实例化的类成员的缺省构造函数除非另外一个构造函数在类初始化或者在构造列表的时候被调用。

拷贝构造函数是程序更加有效率,因为它不用再构造一个对象的时候改变构造函数的参数列表。设计拷贝构造函数是一个良好的风格,即使是编译系统提供的帮助你申请内存默认拷贝构造函数。事实上,默认拷贝构造函数可以应付许多情况。

以下讨论中将用到的例子:

class CExample

{

public:

CExample()

~CExample()

void Init(int n)

private:

char *pBuffer//类的对象中包含指针,指向动态分配的内存资源

int nSize

}

这个类的主要特点是包含指向其他资源的指针。

pBuffer指向堆中分配的一段内存空间。

一、拷贝构造函数

int main(int argc, char* argv[])

{

CExample theObjone

theObjone.Init40)

//现在需要另一个对象,需要将他初始化称对象一的状态

CExample theObjtwo=theObjone

...

}

语句"CExample theObjtwo=theObjone"用theObjone初始化theObjtwo。

其完成方式是内存拷贝,复制所有成员的值。

完成后,theObjtwo.pBuffer==theObjone.pBuffer。

即它们将指向同样的地方,指针虽然复制了,但所指向的空间并没有复制,而是由两个对象共用了。这样不符合要求,对象之间不独立了,并为空间的删除带来隐患。

所以需要采用必要的手段来避免此类情况。

回顾以下此语句的具体过程:首先建立对象theObjtwo,并调用其构造函数,然后成员被拷贝。

可以在构造函数中添加 *** 作来解决指针成员的问题。

所以C++语法中除了提供缺省形式的构造函数外,还规范了另一种特殊的构造函数:拷贝构造函数,上面的语句中,如果类中定义了拷贝构造函数,这对象建立时,调用的将是拷贝构造函数,在拷贝构造函数中,可以根据传入的变量,复制指针所指向的资源。

拷贝构造函数的格式为:构造函数名(对象的引用)

提供了拷贝构造函数后的CExample类定义为:

class CExample

{

public:

CExample()

~CExample()

CExample(const CExample&)//拷贝构造函数

void Init(int n)

private:

char *pBuffer//类的对象中包含指针,指向动态分配的内存资源

int nSize

}

CExample::CExample(const CExample&RightSides) //拷贝构造函数的定义

{

nSize=RightSides.nSize//复制常规成员

pBuffer=new char[nSize]//复制指针指向的内容

memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof(char))

}

这样,定义新对象,并用已有对象初始化新对象时,CExample(const CExample&RightSides)将被调用,而已有对象用别名RightSides传给构造函数,以用来作复制。

原则上,应该为所有包含动态分配成员的类都提供拷贝构造函数。

拷贝构造函数的另一种调用。

当对象直接作为参数传给函数时,函数将建立对象的临时拷贝,这个拷贝过程也将调同拷贝构造函数。

例如

BOOL testfunc(CExample obj)

testfunc(theObjone)//对象直接作为参数。

BOOL testfunc(CExample obj)

{

//针对obj的 *** 作实际上是针对复制后的临时拷贝进行的

}

还有一种情况,也是与临时对象有关的

当函数中的局部对象被被返回给函数调者时,也将建立此局部对象的一个临时拷贝,拷贝构造函数也将被调用

CTest func()

{

CTest theTest

return theTest

}

二、赋值符的重载

下面的代码与上例相似

int main(int argc, char* argv[])

{

CExample theObjone

theObjone.Init(40)

CExample theObjthree

theObjthree.Init(60)

//现在需要一个对象赋值 *** 作,被赋值对象的原内容被清除,并用右边对象的内容填充。

theObjthree=theObjone

return 0

}

也用到了"="号,但与"一、"中的例子并不同,"一、"的例子中,"="在对象声明语句中,表示初始化。更多时候,这种初始化也可用括号表示。

例如 CExample theObjone(theObjtwo)

而本例子中,"="表示赋值 *** 作。将对象theObjone的内容复制到对象theObjthree,这其中涉及到对象theObjthree原有内容的丢弃,新内容的复制。

但"="的缺省 *** 作只是将成员变量的值相应复制。旧的值被自然丢弃。

由于对象内包含指针,将造成不良后果:指针的值被丢弃了,但指针指向的内容并未释放。指针的值被复制了,但指针所指内容并未复制。

因此,包含动态分配成员的类除提供拷贝构造函数外,还应该考虑重载"="赋值 *** 作符号。

类定义变为:

class CExample

{

...

CExample(const CExample&)//拷贝构造函数

CExample&operator = (const CExample&)//赋值符重载

...

}

//赋值 *** 作符重载

CExample &CExample::operator = (const CExample&RightSides)

{

nSize=RightSides.nSize//复制常规成员

char *temp=new char[nSize]//复制指针指向的内容

memcpy(temp,RightSides.pBuffer,nSize*sizeof(char))

delete []pBuffer//删除原指针指向内容 (将删除 *** 作放在后面,避免X=X特殊情况下,内容的丢失)

pBuffer=NULL

pBuffer=temp //建立新指向

return *this

}

三、拷贝构造函数使用赋值运算符重载的代码。

CExample::CExample(const CExample&RightSides)

{

*this=RightSides //调用重载后的"="

}

#include <iostream>

using namespace std

template <class T>

class CMatrix

{

private :

T **Mat //矩阵头指针

int nRow //矩阵的行数

int nCol //矩阵的列数

public :

CMatrix(int row=4,int col=4)

{

Mat = new T*[row]()

for (int i = 0i <row++i) {

T* tmp = new T[col]()

Mat[i] = tmp

}

nRow = row

nCol = col

} //缺省构造函数

void SetCMatrix(int row, int col, const T&data)

{

Mat[row][col] = data

}//键盘输入

void show()

{

for (int i = 0i <nRow++i) {

for (int j = 0j <nCol++j)

cout <<Mat[i][j] <<" "

cout <<endl

}

} //输出

void InputFromFile(){} //从文件中输入

~CMatrix(){} //析构函数

CMatrix(const CMatrix<T>&m)

int GetnRow() const //得到矩阵行值

{

return nRow

}

int GetnCol() const //得到矩阵列值

{

return nCol

}

template <class T>

friend CMatrix<T>operator +(CMatrix<T>&mat1,CMatrix<T>&mat2){} //重载加法

template <class T>

friend CMatrix<T>operator *(CMatrix<T>&mat1,CMatrix<T>&mat2){} //重载乘法

template <class T>

friend CMatrix<T>operator -(CMatrix<T>&mat1,CMatrix<T>&mat2){} //重载减法

}

template <typename T>

CMatrix<T>::CMatrix(const CMatrix<T>&m)

{

Mat = new T*[m.nRow]

for (int i = 0i <m.nRow++i) {

T* tmp = new T[m.nCol]()

Mat[i] = tmp

}

for (int i = 0i <m.nRow++i)

for (int j = 0j <m.nCol++j)

Mat[i][j] = m.Mat[i][j]

nRow = m.nRow

nCol = m.nCol

}

int main()

{

CMatrix<int>a(2, 3)

CMatrix<int>b = a

cout <<b.GetnCol() <<endl

a.SetCMatrix(0, 0, 5)

a.SetCMatrix(0, 1, 2)

a.SetCMatrix(1, 2, 3)

cout <<"Show Matrix a:" <<endl

a.show()

cout <<"Show Matrix b:" <<endl

b.show()

CMatrix<int>c = a

cout <<"Show Matrix c:" <<endl

c.show()

a.SetCMatrix(0, 0, 9)

a.SetCMatrix(1, 0, 4)

cout <<"Show Matrix a:" <<endl

a.show()

cout <<"Show Matrix c:" <<endl

c.show()

}

为了得以体现输出结果,我稍微补了一些函数的实现(如,构造函数,set,show)。

输出结果为:

3

Show Matrix a:

5 2 0

0 0 3

Show Matrix b:

0 0 0

0 0 0

Show Matrix c:

5 2 0

0 0 3

Show Matrix a:

9 2 0

4 0 3

Show Matrix c:

5 2 0

0 0 3

Press any key to continue . . .

你的程序大致来说没有什么问题,无非就是少用了const之类的。所以我稍微加了一两个意思一下。

你不是主要问拷贝构造函数吗?最好给参数加上const,使用引用而不实用传值,是由于引用比传值高效,但是引用有弊病,那就是可能修改传进来的值。在这里我们要确保传进来的矩阵没有被修改(不能被修改),所以加上const来起限制作用(除非有特殊的需求,如标准库中auto_ptr,否则拷贝构造函数的写法就是我写的那种)。

给你再做一个更为复杂但是普遍用于STL的做法,即

vector <int>a

vector<double>d = a

两个类型不同,但是赋值从是允许的!

代码实现如下:

#include <iostream>

using namespace std

template <typename T>

class CMatrix

{

private :

T **Mat //矩阵头指针

int nRow //矩阵的行数

int nCol //矩阵的列数

public :

CMatrix(int row=4,int col=4)

{

Mat = new T*[row]()

for (int i = 0i <row++i) {

T* tmp = new T[col]()

Mat[i] = tmp

}

nRow = row

nCol = col

} //缺省构造函数

void SetCMatrix(int row, int col, const T&data)

{

Mat[row][col] = data

}//键盘输入

void show()

{

for (int i = 0i <nRow++i) {

for (int j = 0j <nCol++j)

cout <<Mat[i][j] <<" "

cout <<endl

}

} //输出

void InputFromFile(){} //从文件中输入

~CMatrix(){} //析构函数

/***** Copy Constructor ******/

template <typename T2>

CMatrix(const CMatrix<T2>&m)

/*****************************/

int GetnRow() const //得到矩阵行值

{

return nRow

}

int GetnCol() const //得到矩阵列值

{

return nCol

}

const T&getData(int row, int col) const

{

return Mat[row][col]

}

T&getData(int row, int col)

{

return Mat[row][col]

}

template <typename T>

friend CMatrix<T>operator + (const CMatrix<T>&mat1, const CMatrix<T>&mat2)//重载加法

template <typename T>

friend CMatrix<T>operator * (const CMatrix<T>&mat1, const CMatrix<T>&mat2)//重载乘法

template <typename T>

friend CMatrix<T>operator - (const CMatrix<T>&mat1, const CMatrix<T>&mat2)//重载减法

}

template <typename T>

template <typename T2>

CMatrix<T>::CMatrix(const CMatrix<T2>&m)

{

Mat = new T*[m.GetnRow()]

for (int i = 0i <m.GetnRow()++i) {

T* tmp = new T[m.GetnCol()]()

Mat[i] = tmp

}

for (int i = 0i <m.GetnRow()++i)

for (int j = 0j <m.GetnCol()++j)

Mat[i][j] = static_cast<T>(m.getData(i, j))

nRow = m.GetnRow()

nCol = m.GetnCol()

}

int main()

{

CMatrix<int>a(2, 3)

CMatrix<int>b = a

cout <<b.GetnCol() <<endl

a.SetCMatrix(0, 0, 5)

a.SetCMatrix(0, 1, 2)

a.SetCMatrix(1, 2, 3)

cout <<"Show Matrix a:" <<endl

a.show()

cout <<"Show Matrix b:" <<endl

b.show()

CMatrix<int>c = a

cout <<"Show Matrix c:" <<endl

c.show()

a.SetCMatrix(0, 0, 9)

a.SetCMatrix(1, 0, 4)

cout <<"Show Matrix a:" <<endl

a.show()

cout <<"Show Matrix c:" <<endl

c.show()

CMatrix<double>d(c)

cout <<"Show Matrix d:" <<endl

d.show()

d.SetCMatrix(0, 0, 2.3)

d.SetCMatrix(1, 0, 5.2)

cout <<"Show Matrix d:" <<endl

d.show()

}

输出结果为:

3

Show Matrix a:

5 2 0

0 0 3

Show Matrix b:

0 0 0

0 0 0

Show Matrix c:

5 2 0

0 0 3

Show Matrix a:

9 2 0

4 0 3

Show Matrix c:

5 2 0

0 0 3

Show Matrix d:

5 2 0

0 0 3

Show Matrix d:

2.3 2 0

5.2 0 3

Press any key to continue . . .

/******注意*******/

template <typename T>

CMatrix<T>::CMatrix(const CMatrix<T>&m)

{

Mat = new T*[m.nRow]

for (int i = 0i <m.nRow++i) {

T* tmp = new T[m.nCol]()

Mat[i] = tmp

}

for (int i = 0i <m.nRow++i)

for (int j = 0j <m.nCol++j)

Mat[i][j] = m.Mat[i][j]

nRow = m.nRow

nCol = m.nCol

}

template <typename T>

template <typename T2>

CMatrix<T>::CMatrix(const CMatrix<T2>&m)

{

Mat = new T*[m.GetnRow()]

for (int i = 0i <m.GetnRow()++i) {

T* tmp = new T[m.GetnCol()]()

Mat[i] = tmp

}

for (int i = 0i <m.GetnRow()++i)

for (int j = 0j <m.GetnCol()++j)

Mat[i][j] = static_cast<T>(m.getData(i, j))

nRow = m.GetnRow()

nCol = m.GetnCol()

}

上面两个两个构造函数的实现略有差异:第二个版本中使用了Mat = new T*[m.GetnRow()]

而第一个版本中则使用了简单的Mat = new T*[m.nRow]

这是由于:在第一个函数中参数const CMatrix<T>&m,其中m的类型是CMatrix<T>,在同一个类中成员可以使用私有成员(nRow)

而第二个函数中参数是const CMatrix<T2>&m,其中m的类型是CMatrix<T>而非CMatrix<T2>,他们输入不同的类型,所以子Matrix<T>不能访问类型为Matrix<T2>m的私有成员。

最后,闲着没事给你加一个赋值运算符的重载和析构函数:(因为有一个规则:当你自己决定手写拷贝构造函数是,你也应该重载赋值运算符和手写析构函数)

完整的程序:

#include <iostream>

using namespace std

template <typename T>

class CMatrix

{

private :

T **Mat //矩阵头指针

int nRow //矩阵的行数

int nCol //矩阵的列数

public :

CMatrix(int row=4,int col=4)

{

Mat = new T*[row]()

for (int i = 0i <row++i)

Mat[i] = new T[col]()

nRow = row

nCol = col

} //缺省构造函数

void SetCMatrix(int row, int col, const T&data)

{

Mat[row][col] = data

}//键盘输入

void show()

{

for (int i = 0i <nRow++i) {

for (int j = 0j <nCol++j)

cout <<Mat[i][j] <<" "

cout <<endl

}

} //输出

void InputFromFile(){} //从文件中输入

~CMatrix()

{

for (int i = 0i <nRow++i)

delete[] Mat[i]

delete[] Mat

} //析构函数

CMatrix(const CMatrix<T>&m)

/***** Copy Constructor 2 ******/

template <typename T2>

CMatrix(const CMatrix<T2>&m)

/*****************************/

template <typename T2>

CMatrix<T>&operator = (const CMatrix<T2>&m)

int GetnRow() const //得到矩阵行值

{

return nRow

}

int GetnCol() const //得到矩阵列值

{

return nCol

}

const T&getData(int row, int col) const

{

return Mat[row][col]

}

T&getData(int row, int col)

{

return Mat[row][col]

}

template <typename T>

friend CMatrix<T>operator + (const CMatrix<T>&mat1, const CMatrix<T>&mat2)//重载加法

template <typename T>

friend CMatrix<T>operator * (const CMatrix<T>&mat1, const CMatrix<T>&mat2)//重载乘法

template <typename T>

friend CMatrix<T>operator - (const CMatrix<T>&mat1, const CMatrix<T>&mat2)//重载减法

}

/*****两个版本都不能少*****/

template <typename T>

CMatrix<T>::CMatrix(const CMatrix<T>&m)

{

Mat = new T*[m.GetnRow()]

for (int i = 0i <m.GetnRow()++i) {

Mat[i] = new T[m.GetnCol()]

}

for (int i = 0i <m.GetnRow()++i)

for (int j = 0j <m.GetnCol()++j)

Mat[i][j] = m.getData(i, j)

nRow = m.GetnRow()

nCol = m.GetnCol()

}

template <typename T>

template <typename T2>

CMatrix<T>::CMatrix(const CMatrix<T2>&m)

{

Mat = new T*[m.GetnRow()]

for (int i = 0i <m.GetnRow()++i) {

Mat[i] = new T[m.GetnCol()]

}

for (int i = 0i <m.GetnRow()++i)

for (int j = 0j <m.GetnCol()++j)

Mat[i][j] = m.getData(i, j)

nRow = m.GetnRow()

nCol = m.GetnCol()

}

/**************************/

template <typename T>

template <typename T2>

CMatrix<T>&CMatrix<T>::operator = (const CMatrix<T2>&m)

{

if ((void*)this != (void*)&m) {

Mat = new T*[m.GetnRow()]

for (int i = 0i <m.GetnRow()++i) {

T* tmp = new T[m.GetnCol()]()

Mat[i] = tmp

}

for (int i = 0i <m.GetnRow()++i)

for (int j = 0j <m.GetnCol()++j)

Mat[i][j] = m.getData(i, j)

nRow = m.GetnRow()

nCol = m.GetnCol()

}

return *this

}

int main()

{

CMatrix<int>a(2, 3)

a.SetCMatrix(0, 0, 5)

a.SetCMatrix(0, 1, 2)

a.SetCMatrix(1, 2, 3)

CMatrix<int>b(a)

b.show()

cout <<b.GetnCol() <<endl

cout <<"Show Matrix a:" <<endl

a.show()

cout <<"Show Matrix b:" <<endl

b.show()

CMatrix<int>c = a

cout <<"Show Matrix c:" <<endl

c.show()

a.SetCMatrix(0, 0, 9)

a.SetCMatrix(1, 0, 4)

cout <<"Show Matrix a:" <<endl

a.show()

cout <<"Show Matrix c:" <<endl

c.show()

CMatrix<double>d = c

cout <<"Show Matrix d:" <<endl

d.show()

d.SetCMatrix(0, 0, 2.3)

d.SetCMatrix(1, 0, 5.2)

cout <<"Show Matrix d:" <<endl

d.show()

CMatrix<int>e(3, 4)

cout <<"Show Matrix e:" <<endl

e.show()

e = d

cout <<"Show Matrix d:" <<endl

d.show()

e = e

cout <<"Show Matrix d:" <<endl

d.show()

}

控制复制的内容也就差不多全了,你的CMatrix类可以安全的使用了!

说的有点多了,因为睡不着!呵呵呵,希望对你有用!

对了,我程序的编译环境:Visual Studio 2010


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/11618292.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-17
下一篇2023-05-17

发表评论

登录后才能评论

评论列表(0条)

    保存