1. error: passing ‘const xxx’ as ‘this’ argument discards qualifiers [-fpermissive]
分析:const修饰实例对象调用了非const修饰的成员方法。
解决方案:将对象变为非const的,或者使用const修饰成员方法
2. error: 'xxx' does not name a type
在复现《C++ Primer》书中的Text Queries源码时,由于多个头文件需要相互包含,就出现上上述的代码。其原因是如果需要声明或者定义一个类的指针的时候,就必须在使用之前,就已经声明或者定义了这个类。否则,编译器就找不到这个类。
(1)在query_base.hpp文件中
#ifndef __QUERY_BASE_HPP__
#define __QUERY_BASE_HPP__
#include "query.hpp"
#include "textQuery.hpp"
#include "queryResult.hpp"
#include <string>
class Query;
class Query_Base{
friend class Query;
protected:
using line_no = TextQuery::data_type;
virtual ~Query_Base() = default;
private:
virtual QueryResult eval(const TextQuery&) const = 0;
virtual std::string rep() const = 0;
};
#endif //__QUERY_BASE_HPP__
在query_base.hpp文件中,Query_Base类需要以Query为友元类。
(2)在query.hpp文件中
#ifndef __QUERY_HPP__
#define __QUERY_HPP__
#include "textQuery.hpp"
#include "queryResult.hpp"
#include "query_base.hpp"
#include <iostream>
#include <memory>
#include <string>
class Query{
friend Query operator~(const Query&);
// friend Query operator&(const Query&, const Query&);
// friend Query operator|(const Query&, const Query&);
friend std::ostream operator<<(std::ostream, const Query&);
public:
Query(const std::string&);
QueryResult eval(const TextQuery& t) const{
return q->eval(t);
}
std::string rep() const{
return q->rep();
}
std::shared_ptr<Query_Base> q;
Query(std::shared_ptr<Query_Base> query):q(query){};
};
#endif //__QUERY_HPP__
如下图所示会出现这类错误:
这是因为在query.hpp中,Query类中还使用到了Query_Base类作为成员变量。这种相互include的方式,会使得编译器无法正确的找到两个类的定义。因此,需要使用声明的方式代替include方式,从而打破这个死循环。
正确的修改方法是,由于Query中需要使用Query_Base的成员方法,因此可以保留include的方式,而在query_base.hpp头文件中注释掉include方式,改用声明的方式。所以,修改后的query_base.hpp文件如下:
(3)补充一下
上述Query_Base类实际上只是一个接口,如果其继承类需要使用到Query的具体方法,该类的实现不应该在query_base.hpp中实现,而应该写在一个新的hpp文件中,并include "query.hpp"头文件。
下面就是在子类中使用了Query实例对象的成员方法,从而导致出现了问题。
争取的方法是将NotQuery放到一个新的头文件中:
这样的话,not_query.hpp中只是单向的包含Query类,而Query中并没有include "not_query.hpp"。
所以强烈建议将接口及其子类,或者基类及其子类都分别写在不同的头文件中。
综上所述,如果是需要在一个A类中简单的声明另一个B类,则使用class B;的形式进行声明就行;如果需要使用B类的成员,则需要include B的头文件。否则,在A中就无法正常的使用B。
参考链接:前置声明与C++头文件互相包含导致的error: 'xxx' does not name a type问题_imred的博客-CSDN博客
3. error.undefined reference to `operator~
分析:operator~声明了两次,但是只定义了一次。可以看一下下面的代码:
namespace A {
struct B {
friend std::ostream& operator<<( std::ostream&, B const & ); // [1]
};
}
std::ostream& operator<<( std::ostream& o, A::B const & ) { // [2]
return o;
}
其中【1】声明了operator<<运算符,但是在【2】中声明并且定义了operator<<运算符。
解决方案:
namespace A {
struct B { friend std::ostream& operator<<( std::ostream&, B const & ); };
std::ostream& operator<<( std::ostream&, B const & );
}
std::ostream& A::operator<<( std::ostream& o, B const & ) {
return o;
}
参考链接:c++ - undefined reference to operator<< - Stack Overflow