运算符重载连接时出错

k-wen 2008-05-10 06:29:05
下面是我编写一个类的头文件(程序还有一个该类的源文件,还有一个主函数的源文件)
不知道为什么当我在main函数里调用该运算符重载时编译连接时会出现下面这样的连接错误
Ractangle.obj : error LNK2005: "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class rectangle const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@
std@@@std@@AAV01@ABVrectangle@@@Z) already defined in main.obj
Debug/FuncClass.exe : fatal error LNK1169: one or more multiply defined symbols found

望人请教,谢谢!


类的头文件

#include<iostream>
#include<vector>
using namespace std;

#ifndef RECTANGLE_H
#define RECTANGLE_H

class rectangle
{
public:
rectangle(double Lent,double wid)
:length(Lent) ,width(wid){ }

virtual ~rectangle() { }

double getLength()const;

double getWidth()const;

double area()const;

void print(ostream & out)const;

private:
double length;
double width;
};

ostream& operator<<(ostream& out,const rectangle& rec)
{
rec.print(out);
return out;
}

#endif
...全文
121 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
k-wen 2008-05-11
  • 打赏
  • 举报
回复
噢,谢谢.你说得对.不过在头文件中我有了
#ifndef RECTANGLE_H
#define RECTANGLE_H
如果该头文件已经被编译一次,则RECTANGLE_H就会被定义了.这样该头文件在别的.cpp文件中就不会被编译.
开始我将运算符重载声明定义都放在.cpp文件.结果就是在编译main.cpp时就报错.因为我在main.cpp里只包
含了rectangle.h,编译器找不到在.cpp里定义的运算符重载函数.

后来我将运算符重载函数的声明定义都放在.h文件....结果单个源文件编译通过了,但是在连接多个源文件的时
候就报错了.

解决的方法...就像上面大家说的..几种方法都可以解决.再次谢谢大家,也谢谢你
arong1234 2008-05-11
  • 打赏
  • 举报
回复
认真看代码是你义务不是人家义务拉:)
你的代码问题就是在头文件里定义函数体,这样每个包含它的cpp文件都会生成一个一摸一样的函数,导致符号重定义错误。需要你把函数定义到cpp文件中,而不是.h文件中

[Quote=引用 9 楼 lihuanming 的回复:]
虽然你并没有很认真的看我的代码,但是你很认真的给我讲解,谢谢你.
[/Quote]
k-wen 2008-05-11
  • 打赏
  • 举报
回复
虽然你并没有很认真的看我的代码,但是你很认真的给我讲解,谢谢你.
星羽 2008-05-10
  • 打赏
  • 举报
回复

// .h改成

#ifndef RECTANGLE_H
#define RECTANGLE_H

class rectangle
{
public:
rectangle(double Lent,double wid)
:length(Lent) ,width(wid){ }

virtual ~rectangle() { }

double getLength()const;

double getWidth()const;

double area()const;

void print(ostream & out)const;

private:
double length;
double width;
};

ostream& operator <<(ostream& out,const rectangle& rec);
#endif

然后再 cpp 里加上

ostream& operator <<(ostream& out,const rectangle& rec)
{
rec.print(out);
return out;
}
cocoolman 2008-05-10
  • 打赏
  • 举报
回复
哦,还有,如果你想把他重载为友元,可你这里又没有friend关键字。

最好的修改如下:

friend ostream& operator < <(ostream& out,const rectangle& rec)

这是最普遍使用的方式
cocoolman 2008-05-10
  • 打赏
  • 举报
回复
首先说明一点,那就是2楼其实已经指出了你的问题所在,那就是缺少了friend关键字.
你要知道,重载的运算符函数可以是: 1、成员函数,2、友元函数,3、非成员非友元函数;这取决于你的实现,你的习惯。
按你上面的实现,你是把<<重载为成员函数,而且是private的,而且它的左操作数是ostream类型的引用。这里犯了3个错误:
首先是访问权限的错误,如果你想把他重载为成员函数,也可以,但你是private的,在类外面就调用不了。应为public。
其次就是参数类型,如果你想他重载为成员函数,那么他的第一个参数就必须是自身类型(或其基类类型的指针或引用)。如果你想把他重载为友元,那么第一个参数就应当是其左操作数的类型。

chendengbiao 2008-05-10
  • 打赏
  • 举报
回复
运算符函数是一种特殊的成员函数友员函数
chendengbiao 2008-05-10
  • 打赏
  • 举报
回复
放到class里面
嵌云阁主 2008-05-10
  • 打赏
  • 举报
回复
ostream& operator < <(ostream& out,const rectangle& rec)
=>
inline ostream& operator < <(ostream& out,const rectangle& rec)
加上inline或者将这个函数实现放到cpp文件中,在头文件中只留声明
chendengbiao 2008-05-10
  • 打赏
  • 举报
回复
friend ostream& operator....
danteliujie 2008-05-10
  • 打赏
  • 举报
回复
全部文件都贴出来
目 录 译者序 前言 第1章 对象的演化 1.1基本概念 1.1.1对象:特性十行为 1.1.2继承:类型关系 1.1.3多态性 1.1.4操作概念:OOP程序像什么 1.2为什么C++会成功 1.2.1较好的C 1.2.2采用渐进的学习方式 1.2.3运行效率 1.2.4系统更容易表达和理解 1.2.5“库”使你事半功倍 1.2.6错误处理 1.2.7大程序设计 1.3方法学介绍 1.3.1复杂性 1.3.2内部原则 1.3.3外部原则 1.3.4对象设计的五个阶段 1.3.5方法承诺什么 1.3.6方法应当提供什么 1.4起草:最小的方法 1.4.1前提 1.4.2高概念 1.4.3论述(treatment) 1.4.4结构化 1.4.5开发 1.4.6重写 1.4.7逻辑 1.5其他方法 1.5.1Booch 1.5.2责任驱动的设计(RDD) 1.5.3对象建模技术(OMT) 1.6为向OOP转变而采取的策略 1.6.1逐步进入OOP 1.6.2管理障碍 1.7小结 第2章 数据抽象 2.1声明与定义 2.2一个袖珍C库 2.3放在一起:项目创建工具 2.4什么是非正常 2.5基本对象 2.6什么是对象 2.7抽象数据类型 2.8对象细节 2.9头文件形式 2.10嵌套结构 2.11小结 2.12练习 第3章 隐藏实现 3.1设置限制 3.2C++的存取控制 3.3友元 3.3.1嵌套友元 3.3.2它是纯的吗 3.4对象布局 3.5类 3.5.1用存取控制来修改stash 3.5.2用存取控制来修改stack 3.6句柄类(handleclasses) 3.6.1可见的实现部分 3.6.2减少重复编译 3.7小结 3.8练习 第4章 初始化与清除 4.1用构造函数确保初始化 4.2用析构函数确保清除 4.3清除定义块 4.3.1for循环 4.3.2空间分配 4.4含有构造函数和析构函数的stash 4.5含有构造函数和析构函数的stack 4.6集合初始化 4.7缺省构造函数 4.8小结 4.9练习 第5章 函数重载与缺省参数 5.1范围分解 5.1.1用返回值重载 5.1.2安全类型连接 5.2重载的例子 5.3缺省参数 5.4小结 5.5练习 第6章 输入输出流介绍 6.1为什么要用输入输出流 6.2解决输入输出流问题 6.2.1预先了解操作符重载 6.2.2插入符与提取符 6.2.3通常用法 6.2.4面向行的输入 6.3文件输入输出流 6.4输入输出流缓冲 6.5在输入输出流中查找 6.6strstreams 6.6.1为用户分配的存储 6.6.2自动存储分配 6.7输出流格式化 6.7.1内部格式化数据 6.7.2例子 6.8格式化操纵算子 6.9建立操纵算子 6.10输入输出流实例 6.10.1代码生成 6.10.2一个简单的数据记录 6.11小结 6.12练习 第7章 常量 7.1值替代 7.1.1头文件里的const 7.1.2const的安全性 7.1.3集合 7.1.4与C语言的区别 7.2指针 7.2.1指向const的指针 7.2.2const指针 7.2.3赋值和类型检查 7.3函数参数和返回值 7.3.1传递const值 7.3.2返回const值 7.3.3传递和返回地址 7.4类 7.4.1类里的const和enum 7.4.2编译期间类里的常量 7.4.3const对象和成员函数 7.4.4只读存储能力 7.5可变的(volatile) 7.6小结 7.7练习 第8章 内联函数 8.1预处理器的缺陷 8.2内联函数 8.2.1类内部的内联函数 8.2.2存取函数 8.3内联函数和编译器 8.3.1局限性 8.3.2赋值顺序 8.3.3在构造函数和析构函数里隐藏行为 8.4减少混乱 8.5预处理器的特点 8.6改进的错误检查 8.7小结 8.8练习 第9章 命名控制 9.1来自C语言中的静态成员 9.1.1函数内部的静态变量 9.1.2控制连接 9.1.3其他的存储类型指定符 9.2名字空间 9.2.1产生一个名字空间 9.2.2使用名字空间 9.3C++中的静态成员 9.3.1定义静态数据成员的存储 9.3.2嵌套类和局部类 9.3.3静态成员函数 9.4静态初始化的依赖因素 9.5转换连接指定 9.6小结 9.7练习 第10章 引用和拷贝构造函数 10.1C++中的指针 10.2C+十中的引用 10.2.1函数中的引用 10.2.2参数传递准则 10.3拷贝构造函数 10.3.1传值方式传递和返回 10.3.2拷贝构造函数 10.3.3缺省拷贝构造函数 10.3.4拷贝构造函数方法的选择 10.4指向成员的指针(简称成员指针) 10.5小结 10.6练习 第11章 运算符重载 1

64,646

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧