const成员函数 , 内联函数 , 友元 , static成员 , N种-构造拷贝构造的优化

本文深入探讨C++中的const成员函数、内联函数、友元函数等特性,解析这些特性的使用场景与注意事项,并通过实例说明如何优化拷贝构造函数。

const修饰成员函数

在成员函数后面加const,意味着this指针指向的对象只读。
这里写图片描述

const修饰了this指针所指向的对象还有一个好处,那就是const形参可以接受const或非const的实参,而非const的形参只能接受非const的实参。


inline(内联)

用inline修饰的成员函数是内联函数,当调用内联函数时,C++编译器会在调用出将内联函数展开,而不会重新开辟函数栈帧,这样做能减少消耗,提升效率。

  • 内联能够减去栈帧的开销,但同时会让代码变得更长,所以有循环,有递归的函数不宜使用内联
  • 内联不是强制执行的,编译器会自己判断是否要将函数展开,像有循环,递归的函数,就算加上inline设置为内联函数,在编译时也会被忽略。
  • inline必须标注在函数定义的前面,标注在声明前面无效。
  • 定义在类内的成员函数时默认的成员函数。

友元(friend)

C++中,类外是不能访问类内的成员的,而友元就可以解决这一问题。

  • 友元函数不算做类的成员函数
  • 在类外可以调用友元函数访问类内的一切成员变量和成员函数。、

甚至可以设置一个友元类,在别的类内就通用了。(即我是你的友元,那在我的类里就可以调用你的成员函数了)

class Date
{
friend void Display( const Date & d);
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
void Display (const Date& d)
{
cout<<"year:" <<d. _year<< endl ;
cout<<"month:" <<d. _month<< endl ;
cout<<"day:" <<d. _day<< endl ;
} v
oid Test ()
{
Date d1 ;
Display(d1 );
}

赋值运算符重载的友元函数:

class Date
{ 
public :
// 1:operator<<可以定义为成员函数吗?
// 2:返回值定义为void可以吗? 为什么?
friend ostream & operator<< ( ostream& os , const Date& d );
friend istream & operator>> ( istream& is , Date& d);

private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};

ostream & operator<<( ostream& os , const Date& d)
{
os<<"year:" <<d. _year<<endl ;
os<<"month:" <<d. _month<<endl ;
os<<"day:" <<d. _day<<endl <<endl;
return os ;
} 

//cin.operator<<(cin, d1)
istream & operator>> ( istream& is , Date& d)
{
cout<<" 请分别输入年月日: "<<endl ;
is>>d ._year;
is>>d ._month;
is>>d ._day;
return is ;
} 

void Test ()
{
Date d1 ;
cin>>d1 ;
cout<<d1 ;
}

友元类:

class Time
{
// Date是Time 的友元, 所以 Date可以访问Time的所有成员。
friend class Date;

private :
int _hour ;
int _minute ;
int _second ;
};

class Date
{
public :
void Display ()
{
cout<<"year:" <<_year<< endl;
cout<<"month:" <<_month<< endl;
cout<<"day:" <<_day<< endl;
// 定义为友元类后, 可以访问Time类对象的所有成员
cout<<"hour:" <<_t. _hour<<endl ;
cout<<"minute:" <<_t. _minute<<endl ;
cout<<"second:" <<_t. _second<<endl <<endl;
}

private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
Time _t ;
};

void Test ()
{
Date d1 ;
d1.Display ();
}

友元一定程度上破坏了C++的封装性,所以不宜多用,慎用友元。


类内的static成员

  • 类内static修饰的成员算作静态类成员,不再算进类的大小
  • 类的静态成员是该类型的对象共享的,这一点与成员函数类似
  • 静态函数参数中没有隐含的this指针,所以静态成员函数不能访问非静态的成员变量

这里写图片描述

N种构造拷贝构造的优化

class AA 
{}; 

AA f (AA a) 
{ 
return a ; 
} 

void Test1 () 
{ 
AA a1 ; 
a1 = f(a1); 
} 

构造 a1调用了一次构造函数,调用函数f传参给a调用一次拷贝构造函数,返回值不是引用,要调用一次拷贝构造函数,赋值给a1调用一次赋值运算符函数重载。

Test1中调用了1+1=2次AA的拷贝构造函数,1次AA的赋值运算符函数的重载。

class AA 
{}; 

AA f (AA a) 
{ 
return a ; 
} 

void Test2 () 
{ 
AA a1 ; 
AA a2 = f(a1); 
} 



创建a1调用一次构造函数,传参给a调用一次拷贝构造函数,返回值传值调用一次拷贝构造函数,但这次传值有立刻作为拷贝给a2的副本,所以省略构建a2的那次拷贝构造函数。
Test2中调用了次 1+1=2 AA的拷贝构造函数 , 0 次AA的赋值运算符函数的重载。

class AA 
{}; 

AA f (AA a) 
{ 
return a ; 
} 

void Test3 () 
{ 
AA a1 ; 
AA a2 = f(f(a1)); 
} 

构建a1调用一次构造函数,传参给a调用一次拷贝构造函数,函数返回值传值调用一次拷贝构造函数,这个返回值又立刻作为外层函数的参数,所以省去了创建形参的那次拷贝构造函数,外层函数返回值传值调用一次拷贝构造函数,因为这次传值立刻有作为创建a2的拷贝副本,所以省去构建a2的那次拷贝构造函数。
Test3中调用了 1+1+1=3 次AA的拷贝构造函数, 0 次AA的赋值运算符函数的重载。

由此可以知道,当拷贝构造完毕紧接着又要调用拷贝构造函数时,编译器会进行优化,省去一次拷贝构造函数,这样能提高效率。

<think>好的,我现在需要帮助用户将之前实现的C++复数代码拆分到多个文件中。用户希望将定义成员函数实现和主函数分别放在不同的文件中,确保结构清晰且功能完整。首先,我得回忆一下C++多文件组织的基本结构。 用户之前提供的代码是一个完整的实现,包在单个cpp文件中。现在需要将其拆分为头文件(.h)、实现文件(.cpp)和主程序文件(main.cpp)。根据引用[1],用户提到分成声明文件(complex.h)、实现文件(complex.cpp)和使用文件(main.cpp)。所以,我应该按照这三个文件来组织。 首先,定义应该放在头文件complex.h中。这里需要包成员变量、静态成员构造函数、运算符重载的友元声明、成员函数声明以及静态计数器的声明。同时,头文件中需要添防止重复包的预处理指令,比如#ifndef、#define和#endif。另外,运算符重载函数如operator+、operator-等是友元函数,它们的声明需要在内部,而定义则在实现文件中。 接下来,成员函数实现放在complex.cpp中。这包括构造函数定义(虽然大部分已经在内联实现,但如果有更复杂的构造可能需要)、运算符重载的具体实现、modulus方法、toString方法以及静态成员count的初始化。需要注意的是,静态成员变量count需要在cpp文件中进行初始化,即int Complex::count = 0;,这部分不能放在头文件中,否则会导致重复定义。 然后,主函数main()放在main.cpp中,这里会包头文件complex.h,并使用复数的各种功能。同时,用户可能需要包必要的库,比如iostream和stdexcept,以确保异常处理能正常工作。 在拆分过程中,需要注意友元函数的处理。例如,operator<<是重载的流插入运算符,它作为友元函数需要在头文件中声明,但定义实现文件中。此外,确保所有成员函数实现文件中正确上Complex::作用域。 还有,用户提到的字符串转换函数toString(),在实现时需要正确生成各种格式,比如处理实部或虚部为零的情况,确保输出符合要求的格式如“1+2i”、“3i”、“7.5”等。这部分逻辑已经在原始代码中处理,拆分时需保持其正确性。 另外,静态成员函数getCount()用于统计对象数量,用户需要确保在每次构造函数包括拷贝构造)中递增count,这在各个构造函数中已经实现,拆分时需保留这些逻辑。 可能遇到的问题包括头文件重复包,所以必须使用预处理指令防止。另外,运算符重载函数作为友元,在头文件中声明时需要正确的参数列表,实现文件中定义时不需要再friend关键字。 最后,测试主函数是否正确调用各个功能,比如减乘除运算、模运算、输出格式以及对象计数。确保拆分后的代码能够编译运行,功能与之前一致。 总结步骤:创建complex.h放置声明,complex.cpp放置成员函数和静态变量的定义,main.cpp放置主函数。编译时需要将complex.cpp和main.cpp一起编译,确保链接正确。</think>以下是符合C++工程化规范的多文件组织方案,基于您之前实现的复数代码进行拆分: ### 文件结构 ``` ├── complex.h // 声明 ├── complex.cpp // 成员函数实现 └── main.cpp // 主函数 ``` ### 1. 声明文件(complex.h) ```cpp #ifndef COMPLEX_H #define COMPLEX_H #include <iostream> #include <string> #include <cmath> class Complex { private: double real; double imag; static int count; // 静态成员声明 public: // 构造函数声明 Complex(double r = 0.0, double i = 0.0); Complex(const Complex& other); explicit Complex(double r); // 运算符重载声明 friend Complex operator+(const Complex& a, const Complex& b); friend Complex operator-(const Complex& a, const Complex& b); friend Complex operator*(const Complex& a, const Complex& b); friend Complex operator/(const Complex& a, const Complex& b); // 成员函数声明 double modulus() const; std::string toString() const; static int getCount(); // 流运算符重载声明 friend std::ostream& operator<<(std::ostream& os, const Complex& c); }; #endif ``` ### 2. 实现文件(complex.cpp) ```cpp #include "complex.h" #include <sstream> #include <stdexcept> // 初始化静态成员 int Complex::count = 0; // 构造函数实现 Complex::Complex(double r, double i) : real(r), imag(i) { ++count; } Complex::Complex(const Complex& other) : real(other.real), imag(other.imag) { ++count; } Complex::Complex(double r) : real(r), imag(0) { ++count; } // 运算符重载实现 Complex operator+(const Complex& a, const Complex& b) { return Complex(a.real + b.real, a.imag + b.imag); } // 其他运算符实现似结构,此处省略节省篇幅) // ... // 成员函数实现 double Complex::modulus() const { return std::sqrt(real*real + imag*imag); } std::string Complex::toString() const { // 保持原有实现逻辑 } std::ostream& operator<<(std::ostream& os, const Complex& c) { os << c.toString(); return os; } // 静态成员函数 int Complex::getCount() { return count; } ``` ### 3. 主函数文件(main.cpp) ```cpp #include "complex.h" #include <iostream> int main() { Complex c1(3, 4); // 3+4i Complex c2(1, -1); // 1-i Complex sum = c1 + c2; std::cout << "Sum: " << sum << std::endl; std::cout << "Total objects: " << Complex::getCount(); return 0; } ``` ### 关键实现说明 1. **头文件保护机制** - 使用`#ifndef COMPLEX_H`防止头文件重复包 - 符合C++工程化规范[^1] 2. **静态成员处理** - 头文件中声明静态成员`count` - 在cpp文件中进行初始化`int Complex::count = 0;` 3. **运算符重载拆分** - 友元运算符在头文件声明 - 在cpp文件中实现具体运算逻辑 4. **编译指令** ```bash g++ -o program complex.cpp main.cpp ``` ### 多文件优势 1. **代码复用性**:其他文件只需包`complex.h`即可使用复数 2. **编译效率**:修改实现文件时无需重新编译主程序 3. **可维护性**:符合面向对象设计的封装原则[^2] 4. **扩展性**:方便添单元测试模块 ### 扩展建议 1. 添`makefile`自动化编译 2. 创建`test.cpp`进行单元测试 3. 使用Doxygen格式添文档注释 4. 实现移动构造函数(C++11特性)提升性能[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值